mike ward content follows

Archive for the 'GEM/plugins' Category

paperclip just worked

Posted in rails, GEM/plugins on November 21st, 2008

OK for a current project I needed to have attached photos for stores. I could have chosen to use attachment_fu, but after seeing the excellent Railscast, I was eager to try paperclip. My opinion - a bit disappointing really, as it was so effortless I didn’t actually learn much at all. No looking through lots of plugin code, no spending hours of googling - no pain!
I grabbed the plugin code since the GEM seems to be out of date? How easy was it? Keep reading.

First I installed the plugin then I ran the migration. Four columns added to my stores table for filename, size, type and timestamp. Frankly I could live without all four, but some projects are gonna use these I suppose.

Next I added a line to the model to which I wanted to have an attachment:

has_attached_file :exterior,

:url => “/images/stores/:attachment/:id.:extension”,
:path => “:rails_root/public/images/stores/:attachment/:id.:extension

I could have also specified multiple different file sizes to save, like 150×200, 400×300, etc.like this:

:styles => { :thumb => “200×150″, :regular => “640×480>” }

Then I added a couple lines to validate the things I cared about:

validates_attachment_size :exterior, :less_than => 100.kilobytes
validates_attachment_content_type :exterior,

:content_type => [’image/jpeg’,'image/png’,'image/gif’]

There’s one “gotcha” in here, in that to change your new and edit forms to work with binary attachments you’re gonna have to change the form action to be mixed/multipart

<% form_for(@store, :html => { :multipart => true }) do |f| %>

Next I went to the view and just refer to the attachment as @store.exterior.url (my stores controller serves up @store), and if I had saved thumbnails and large versions I could have specified which one I wanted to display.

Now I am saving these store images in a shared directory. So when I deploy, I have a task defined in capistrano that runs right after the deploy:symlink that also puts symlink in the public/images/stores directory pointing to this shared store photo store (pun intended) But I need to run a background task to back up those images periodically, or I’ll forget about them until one day…..

Long story short, I decided to see how easy it was to tell Paperclip to save them in my Amazon s3 account instead of the filesystem. Yeah you guess it - pretty tame. Here’s the revised store.rb snippet:

has_attached_file :exterior,

:storage => :s3,
:bucket => “pizza.pro.stores.exteriors”,
:s3_credentials => “#{RAILS_ROOT}/config/s3.yml”,
:path => “:id.:extension”

Don’t ask why I am using such a ridiculously named bucket, but I am. Anyway the 2 keys for s3 are kept in a YAML file as you can see. I treat it just like my database.yml file, and don’t version it, but simply keep in :rails_root/shared/config/ and create a symlink to it on every deploy.
Now you may ask, how can this be such a happy plugin experience. Well if I have to criticize, it would be that I see it added 4 columns to my stores table. In my case I could get by with less. But I think the main point is if I had a half dozen attachments per model, like for a real estate app with exteriors, kitchens, family rooms, etc. then this table could not be allowed to grow that wide.

But hey, if the app is featuring photos as a central item, shouldn’t you have a model just for your attachments? Add one column to refer back to the model it belongs_to and you’re golden. That’s really not so terrible.