Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

One does not simply delete an Arc attachment #40

Open
jerodsanto opened this issue Jul 27, 2016 · 10 comments
Open

One does not simply delete an Arc attachment #40

jerodsanto opened this issue Jul 27, 2016 · 10 comments

Comments

@jerodsanto
Copy link

Let's say I want to delete an image attachment, but not replace it with a new one. I can't seem to figure out how to get that done.

I tried replacing the file field with a hidden field of same name and nil value or "" value:

<%= hidden_input f, :logo_image, value: "" %>

But that gives me:

no function clause matching in Arc.Actions.Store.store/2

When calling cast_attachments. I know there is an Arc.Actions.Delete, but I don't know how to invoke it.

If you lend me a hand I'd be happy to update the README to include this procedure.

Thanks in advance. 🍻

@brayhoward
Copy link

brayhoward commented Aug 27, 2016

@jerodsanto I fugured out a way to delete the image going by the documentation for delete in the Arc README

Assuming you have already stored and uploaded an avatar to this user deleting it will look something like this.

# With a scope:
user = Repo.get! User, 1
path = YourApp.Avatar.url({user.avatar, user})

Avatar.delete({path, user})

The problem is that it only deletes the the image from wherever your storing it at, ex: S3, but doesn't remove the path url that is associated to the model.
so calling YourApp.Avatar.url({user.avatar, user}) returns a broken url which isn't worth a fuck really.

If I figure out how to get the correct behavior I'll post an update here.

@stavro
Copy link
Owner

stavro commented Aug 27, 2016

There is no convenience yet for deleting objects through Ecto / arc_ecto. I will consider adding this.

However, to delete for now, the best option is likely to:

  1. Update the user to remove the reference to the avatar (do this first, so all new image urls will result in nil or the default url. You never want to show a url to a removed object, which can happen if you don't do this first.
  2. After the record is nillified, remove it from the file storage (this can even be done async, as it will be a slower operation).
user = Repo.get!(User, 1) # Assume there is a property :avatar on User

user
|> User.changeset(%{avatar: nil})
|> Repo.update!()

:ok = Avatar.delete({user.avatar, user})

# Since the above deletion doesn't really need to happen synchronously, you can delete it asynchronously to speed up the request/response.
# spawn(fn -> Avatar.delete({user.avatar, user}) end)

@brayhoward
Copy link

Thank you @stavro.
This is much better than what I was trying to implement!

@brayhoward
Copy link

This is pretty straight forward. I think updating the readme will be sufficient. I'll do that tomorrow and submit a PR. Thanks again.

@brayhoward
Copy link

When calling User.changeset(user, %{avatar: nil})

It's raising this error:
(FunctionClauseError) no function clause matching in Arc.Actions.Store.store/2

Any thoughts on what to do next?

@stavro
Copy link
Owner

stavro commented Aug 27, 2016

Ah - if you currently send nil through cast_attachments it will fail.

Ok - for now send it through cast or use change directly:

Ecto.Changeset.change(user, %{avatar: nil})

rather than sending through cast_attachments. I'll get this fixed shortly.

@mamantoha
Copy link

When I try to delete attachment from iex -S mix nothing happens:

attachment = Repo.get Attachment, 1
path = Rumbl.Image.url({attachment.file, attachment})
Rumbl.Image.delete({path, attachment})

It returns :ok but the file still exists on the hard drive.

@bchase
Copy link

bchase commented Jan 12, 2017

@mamantoha I was running into the same issue, but got things working with:

attachment = Repo.get Attachment, 1
path = Rumbl.Image.url({attachment.file, attachment})
[path | _] = String.split path, "?" # strips the "?v=1234" from the URL string
Rumbl.Image.delete({path, attachment})

Or perhaps more idiomatically:

attachment = Repo.get Attachment, 1
path =
  Rumbl.Image.url({attachment.file, attachment})
  |> String.split("?")
  |> List.first 
Rumbl.Image.delete({path, attachment})

Apparently the return from Image.url/1 needs to be trimmed as follows to make it usable by Image.delete/1:

"/foo/bar?v=1234"
"/foo/bar"

Hope this helps!

@GBH
Copy link

GBH commented Mar 24, 2017

Deleting seems to remove file(s), but not directory it was in.

@jgonera
Copy link

jgonera commented Jan 18, 2019

Are there any plans to add an easier / more automatic way of removing files? Ideally I would like to just set the property for my attachment to nil and have arc_ecto take care of removing the file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants