Making Dynamic Paths for Paperclip

Rohit Sharma 2010-12-03
Making Dynamic Paths for Paperclip

If you ever want to upload and save files in your rails app, you can use this gem Paperclip.

According to the owner of this gem

Paperclip is intended as an easy file attachment library for ActiveRecord. The intent behind it was to keep setup as easy as possible and to treat files as much like other attributes as possible. This means they aren’t saved to their final locations on disk, nor are they deleted if set to nil, until ActiveRecord::Base#save is called. It manages validations based on size and presence, if required. It can transform its assigned image into thumbnails if needed, and the prerequisites are as simple as installing ImageMagick (which, for most modern Unix-based systems, is as easy as installing the right packages). Attached files are saved to the filesystem and referenced in the browser by an easily understandable specification, which has sensible and useful defaults.
This gem proves to be very helpful in attaching and uploading files to your rails-app. You can read the implementation guide on the site. What I am basically focussing on is how can we create dynamic path for storing the files uploaded using Paperclip.

So here’s what my senior colleague Rohit Pal did to workaroud this situation.

Previously we had these settings

has_attached_file :user_image
                 :url => "../assets/users/#{self.name}_:basename_:id" + ".:extension",
                 :path => ":rails_root/public/assets/users/#{self.name}_:basename_:id" + ".:extension"

This would save the file in the RAILS_ROOT/public/assets/users/ directory. But we wanted to store it in RAILS_ROOT/public/assets/users/#{user_id} directory. i.e. we wanted to create a separate directory for each and every user in our app.

We tried to use this

has_attached_file :user_image
                 :url => "../assets/users/#{self.user.id.to_s}/#{self.name}_:basename_:id" + ".:extension",
                 :path => ":rails_root/public/assets/users/#{self.user.id.to_s}/#{self.name}_:basename_:id" + ".:extension"

But it didn’t work. We also studied many tutorials but they didn’t seem to work for us. After some time Rohit peeped into the Paperclip::Interpolations module and came across the methods basename, id, extension etc. These methods are the one which provide for the tags used in the path and url of paperclip.

So we ended up making a helper in config/initializers directory. What we decided to do is, overwrite the Paperclip::Interpolations module and add a method user_id in it, which will retrun us the user id. Here’s the code for the helper.

module Paperclip
    module Interpolations
        def user_id attachment, style_name
            attachment.instance.user_id
        end
    end
end

And now we use this

has_attached_file :user_image
                 :url => "../assets/users/:user_id/#{self.name}_:basename_:id" + ".:extension",
                 :path => ":rails_root/public/assets/users/:user_id/#{self.name}_:basename_:id" + ".:extension"

and now it stores the file in RAILS_ROOT/assets/users/1/ directory. And that’s what we wanted to do.

Thanks. Have a great day. :D