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

About these ads

3 comments

  1. Great post, was just what I needed to fix the exact same issues I have having.. I changed it around a bit to not add the model name but it worked perfect.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s