Use before_destroy on a model with paperclip
I have an application that I’m working on, this application has a demand that I will show the total files and the file total size inside a project. Here is my model:
Of course I have the option of using joins and so on and then calculating the file size, but because every project has many folders and every folder has many attachments this seems a bit off and not straight forward.
This is absolutely not the Rails way of doing things, so what I added a couple of fields inside the project model and here is what my model looked like after the change:
Now, I have straight forward fields inside my model, and the database work is very light, fast and straight forward. I added an observer for the attachment model, just to update the count and the total file size in the project model.
Here’s my observer’s code:
[ruby]
class AttachmentObserver < ActiveRecord::Observer
observe :attachment
def after_create(record)
project = record.project
if project
project.increment!(:file_count, 1)
project.increment!(:file_size, record.sketch_file_size) unless record.sketch_file_size.nil?
end
return true
end
def before_destroy(record)
project = record.project
if project
project.decrement!(:file_count, 1)
project.decrement!(:file_size, record.sketch_file_size) unless record.sketch_file_size.nil?
end
return true
end
end
[/ruby]
I added the observer to the application configuration.
Now, everything seemed to be working fine on create, when I deleted a model (deleted an attachment) I got a nil exception on the skecth_file_size property. The problem is that the paperclip plugin deleted the sketch file before my callback and so prevented me from using it.
This required a patch to the paperclip plugin.
Inside the paperclip plugin there’s a file called paperclip.rb
Ffor me, it was line 242, I changed it from before_destroy to after_destory like so:
[ruby]
after_destroy :destroy_attached_files
[/ruby]
Now, also in attachment.rb (also in paperclip plugin)
For me it was line 335:
[ruby]
unless instance.frozen?
instance_write(:file_name, nil)
instance_write(:content_type, nil)
instance_write(:file_size, nil)
instance_write(:updated_at, nil)
end
[/ruby]
This worked like a charm and now my callback works, updating the model of the project as the files are adding and deleting, I don’t have to do complicated joins to get simple data.
Here’s how it looks in my application now:
This is the code I use to make it happen:
[ruby]
<%= @project.name %>
[/ruby]