s

Changing Paperclip File Storage Location

Jan 11, 2009

For a while at Plexus, we've been using FileColumn for all our image/file upload attachment needs. It's worked out really well, but when we saw Paperclip we thought it might be a better choice.

Paperclip is super easy to setup and use, but we found ourselves wanting to slightly change the default way it stored attachments. We were used to the way that FileColumn created its folder structure. It would make a folder named for the model (singular) that the attachment(s) were part of and a folder for each attachment (singular). Say we had a BlogPost model with an image attachment and a file attachment. FileColumn would make the following two folders: public/blog_post/image and public/blog_post/file.

Paperclip operates a little differently. It creates a folder (plural) in public for each attachment. If you had the same setup as before, Paperclip would create the following two folders: public/images and public/files. Can you see the immediate problem with this? We already have a public/images folder in our default Rails file structure, so this might get a little confusing. Another problem arises if we have several models with an image attachment. Paperclip would store them all in the same folder. This would be ok 99% of the time. See, Paperclip gets images by their id and name, so even if two models have image attachments and the same id, as long as the name is different, we're ok. But, if you somehow add a different image with the same name, to a model with the same id, then it would get overwritten. Not very likely, but still possible.

The great thing about Paperclip is that you can change the default way it stores its attachments. You can just past a few extra options to the has_attached_file call in your model. As of the current version of Paperclip, they have fixed the file structure problem by tweaking the default storage path. They added a system subfolder in the public folder. This has a two-fold benefit. First, we don't have the problem before of having an attachment named image. Second, this works great for Capistrano because the system folder is already symlinked from the public folder, so you don't have to worry about adding symlinks to your deploy file.

Anyway, back to my point of changing the default file storage path. You can just add the url (which tells where to retrieve the files) and path (which tells where to save the file) options to your has_attached_file call in the model. We add the :class option to include the model_name as a folder.

has_attached_file :image,
  :styles => {:thumb => '120x120>', :large => '640x480>' },
  :default_style => :thumb,
  :url => "/system/:class/:attachment/:id/:style/:basename.:extension",
  :path => ":rails_root/public/system/:class/:attachment/:id/:style/:basename.:extension"

NOTE: Thanks to commenter Steve Bartz for pointing out that current versions of Paperclip have the default path set to ":rails_root/public:url". Because of this, you can leave out the :path option.

So, now our folder structure for the original example would be public/system/blog_posts/images and public/system/blog_posts/files. Much better!

Just make sure you put the whole path in the :path option using the :rails_root variable.

Tagged: railsrubypapercliptutorial