Using Amazon’s CloudFront with Rails & Paperclip 5

Posted by Barry on September 08, 2009

It took me a bit of experimentation, and I never found an example in a single place that showed how to set it up exactly how I wanted, so here is my code in my model for storing images used by the ArtCat calendar on Amazon S3. I am using Paperclip version 2.3.1.

First you will need to set up the distribution in Amazon for your given bucket, so that you have a URL to use for the :s3_host_alist value. I also set up a CNAME so that I can use a nice url like calcdn.artcat.com.

Note that I don’t want to store any images other than my resized ones, so my :default_style is set to :original. Some of these values are actually constants in my config files, but I’ve replaced those here to make it more clear.

    has_attached_file :image,
      :storage => 's3',
      :s3_credentials => "#{RAILS_ROOT}/config/s3_credentials.yml",
      :bucket => 'artcal-production',
      :s3_host_alias => 'calcdn.artcat.com',
      :url => ':s3_alias_url',
      :path => "images/:class/:id_:timestamp.:style.:extension",
      :styles => { :thumb  => '60x60#', :medium => '270x200#', :original  => '600x600>' },
      :default_style => :original,
      :default_url => 'http://cdn1.artcat.com/pixel.gif',
      :s3_headers => { 'Expires' => 1.year.from_now.httpdate },
      :convert_options => { :all => '-strip -trim' }

Note that you do NOT have to set the ActionController::Base.asset_host to your CNAME for images. Paperclip just handles it as expected for these images.

You’ll notice an interpolation in the :path that is not standard. Thanks to this Intridea Company Blog post I learned that I will need to change my image names when they are updated. CloudFront will not update my image due to that Expires header I set above for a whole year, which is not what we want to happen. I solved this by including the timestamp based on the updated_at value for the image. Based on that Intridea post, this is the code I added to config/initalizers/paperclib.rb.

Paperclip.interpolates(:timestamp) do |attachment, style|
  attachment.instance_read(:updated_at).to_i  
end

At first I was storing the images on the file system and serving them via Apache. Moving them to CloudFront improved my page load times by at least 50%, and means that I don’t have to run as powerful as server to handle a lot of traffic on this image-heavy site as I might otherwise need.

Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

  1. Mike Champion Sat, 19 Sep 2009 20:22:20 EDT

    Thanks for this post, it was very helpful in setting up our app with Cloudfront! Exactly what I was looking for.

  2. Barry Sat, 19 Sep 2009 20:41:53 EDT

    I’m glad to hear it helped!

  3. Marco B Thu, 29 Oct 2009 03:33:42 EDT

    Thanks for the post.

    I know CloudFront has a 24hours delay to refresh its content if you update a file of yours into S3, so the “change name” does the trick (renaming a file is also the only way to be sure that browser don’t use a locally cached version).

    Nice way to implement this into paperclip, thanks again :)

  4. Cameron Westland Fri, 29 Jan 2010 11:14:15 EST

    Be careful with the updated_at interpolator if you’re going to have any other attributes on the model. For instance. If you have :image and :name in the database. If you do Model#update_attribute(:name, “New name”) it will update your Interpolation for the attachment. It will not however update the file name on the server so you’re path and the actual file will be out of sync.

  5. Barry Fri, 29 Jan 2010 13:13:52 EST

    Hello, Cameron. It doesn’t work that way. The interpolation is using attachment.instance_read(:updated_at).to_i so it only changes if the file changes, not if anything else on the model changes. The problem you describe only happens if you are relying on Model.updated_at for the interpolation.

Comments