19

I'm having a hard time figuring out how to prevent Paperclip from deleting the old version of an attachment (image).

I have a model, Site, which has an attachment, logo. I would like to keep the old logos around since I will be keeping track of changes to the model and would like to view the history of logos.

I'm keeping track of the changes in another model, which has a reference to file paths. My problem is that when updating a site with a new logo, Paperclip will flush the old logo first.

It surprises me that there's not an option you can switch to prevent Paperclip from flushing the old attachment before creating the new one.

Any ideas?

simonwh
  • 1,017
  • 8
  • 21

4 Answers4

32

There's a new option that tells paperclip to preserve old attachments:

https://github.com/thoughtbot/paperclip/commit/65e8d4f6de50732d8e1b https://github.com/thoughtbot/paperclip/issues/60

Simple to use:

has_attached_file => :attachment,
                     :styles => { :thumb => 100x100! },
                     :preserve_files => true

It's not documented yet and took some digging to find so I wanted to share it here.

Will Koehler
  • 1,746
  • 22
  • 16
  • Thank you. +1 from here, even though you didn't solve my problem at the time. – simonwh Oct 31 '11 at 21:28
  • 5
    As of today, `preserve_files` seems deprecated, for the latest paperclip API: http://rubydoc.info/gems/paperclip/Paperclip/ClassMethods:has_attached_file See `keep_old_files`: Keep the existing attachment files (original + resized) from being automatically deleted when an attachment is cleared or updated. Defaults to false. – Adrien Schuler Jun 13 '13 at 15:40
  • 1
    @AdrienSchuler I read those two as being separate. `preserve_files` will keep files even if the parent record is deleted, where as `keep_old_files` doesn't give this assurance. – Joshua Pinter Aug 13 '14 at 17:10
  • Is anybody else noticing that Paperclip still sets all the attachment attributes to `nil` when destroying? This makes it hard to just clear the `deleted_at` attribute to restore the record because all the important attributes are set to `nil`. – Joshua Pinter Jun 27 '16 at 19:23
  • is there any solution to avoid paperclip to set these attributes as NIL ? @JoshuaPinter – kashif Feb 19 '18 at 14:46
  • @Kashif Not that I found, I don't think. – Joshua Pinter Feb 20 '18 at 04:33
  • @JoshuaPinter thanks. i want to delete and then undelete later. so, i kept a separate DB field :( – kashif Feb 20 '18 at 06:26
  • @Kashif What is your "separate DB field"? Something like `deleted_at`? – Joshua Pinter Feb 20 '18 at 19:38
  • @JoshuaPinter i marked a record as archived and will restore it later. i kept is_archived a boolean field – kashif Feb 21 '18 at 19:04
  • @Kashif Nice one. Hopefully we can get this properly fixed at some point, though. – Joshua Pinter Feb 21 '18 at 20:15
1

Because attachments are defined at the class level, Paperclip interpolates the symbols in your strings using it's own interpolation library. You can create your own interpolations using this library.

I would add a field to the model called attachment_version or something similar, and then increment this version number each time the file is changed. Then, create an interpolation for it in an initializer file:

Paperclip.interpolates :version do |attachment, style|
  attachment.instance.attachment_version
end

Now you can use :version in your strings:

class Model < ActiveRecord::Base
  has_attached_file :something, :path => " :rails_root/public/somethings/etc/:version.:extension"
end

See the wiki documentation for more information.

[Update]

After some digging around (see the comments to this answer), I've come to the conclusion that Paperclip will still delete the old attachment due to code that's called in Paperclip::Atachment#attach. Probably the best way to deal with this is to create a new storage engine based on Paperclip::Storage::Filesystem and overwrite #flush_deletes. Note that there is no way in that method to tell if a file is being queued for deletion because of the model it belongs to being deleted or a new file is being uploaded in its place.

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • It occurs to me that Paperclip may still delete the old file, just by default, even if the names do not match... – Michelle Tilley Feb 06 '11 at 03:41
  • 1
    This appears to be the case. `Paperclip::Attachment#assign` calls `#clear`, which calls `queue_existing_for_delete`, which in turn does exactly what it sounds like it does. You *could* create a new storage engine based on https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/storage/filesystem.rb and modify `#flush_deletes` as necessary. – Michelle Tilley Feb 06 '11 at 03:59
  • Thanks BinaryMuse, that seems to be the best way to go about it at the moment. You should create an answer ;-) – simonwh Feb 06 '11 at 10:51
1

lib/paperclip_monkey_patch.rb:

module Paperclip
  class Attachment
   def clear
    # nop
    #raise "hell"
    # op
    instance_write(:file_name, nil)
    instance_write(:content_type, nil)
    instance_write(:file_size, nil)
    instance_write(:updated_at, nil)
  end
 end
end

Then add this line at the top of any file that deleted attachments:

require 'paperclip_monkey_patch'

Thanks to Ruby Forum

paxer
  • 961
  • 10
  • 17
0

I had a similar issue with Paperclip attachments at when working on a Rails blog last summer.

There is a patch that addresses this. I wasn't able to get it working for myself, but it's worth a shot!

http://github.com/alainravet/paperclip/tree/keep_old_files