Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails and paperclip, delete the record but don't delete the attachment

I'm using rails and paperclip to save images, the usual way.

When a record with an attachment is destroyed, the attachment also gets deleted from the file system.

99% of the time this is the correct action, however there is a case where I need the attachment to remain in the system even though the db record is deleted.

I was wondering if anyone knew how to do this.

I've tried setting the attachment fields to nil via an update_attribute before destroying the record, but the update_attribute also delete the file.

One way would be to ignore all the callbacks, however some of the other call backs are needed and this seems a little too much. Anyone know any better ways...

Cheers.

like image 200
MintDeparture Avatar asked May 16 '11 07:05

MintDeparture


4 Answers

you may want to take a look at how Attachment#assign (called when you do object.attachment = new_attachment) is implemented in paperclip. Basically, it makes a bit of setup, then calls Attachment#clear, then it saves the new file.

Attachment#clear puts the old file in a deletion queue that is processed when you call save again, what you want is simply to avoid the call to clear, which you could do by either writing a new assign method which skips that line or by monkey patching #clear so that it becomes a no-op. In theory you could just monkey patch it on the instances where you want this to happen, but it seems to me you may want to do it for the whole project.

Or you can clear the instance variable holding the processing queue. That variable does not have an accessor, but it should be trivial to do an instance_variable_get

like image 166
riffraff Avatar answered Nov 05 '22 12:11

riffraff


The gem allows you to do a soft delete:

(from paperclip)

File Preservation for Soft-Delete

An option is available to preserve attachments in order to play nicely with soft-deleted models. (acts_as_paranoid, paranoia, etc.)

has_attached_file :some_attachment, {
    preserve_files: true,
}

This will prevent some_attachment from being wiped out when the model gets destroyed, so it will still exist when the object is restored later.

like image 34
Alex Falke Avatar answered Nov 05 '22 11:11

Alex Falke


Nil-ling the database fields that paperclip generates (file_name, content_type, file_size) would not keep the file. The destroy method will still point it through the index.

Try changing the id to some random number (e.g. 999898) before you destroy the record. If it throws exception, also nil the fields. That way the record will no longer points at the file and will remain as the record gets destroyed.

like image 1
KMC Avatar answered Nov 05 '22 11:11

KMC


So the question is what is going on? You are trying to implement undo so someone can delete and then undelete?

I would argue that your solution should be dealing with a "clear" flag and then deleting in a batch job nightly if the clear flag is true. Would not impact performance as long as all gets are for records where clear = false with an index. The question just has a feel of "wrongness" in the solution to it. Just offering a different perspective.

like image 1
Dmitriy Likhten Avatar answered Nov 05 '22 10:11

Dmitriy Likhten