Deploying Rails 3.1 applications with Capistrano

I’m currently working on an application using the latest RC of Rails 3.1 (rc5, which is actually quite stable). In Rails 3.1 there is a new Asset Pipeline which now handles images, stylesheets, javascripts etc differently, especially when it comes to the filename.

In a Rails 3.0 or Rails 2.3 app, by default, a cache busting parameter is appended to the resource URL, for example: http://www.something.com/images/monkeys.jpg?138767865 – this number appended to the end if the mtime of the file from that server. When this was first put into place this was great, it worked as prescribed and was easy to manage, however there are some behaviours which this technique brings along with it:

  • Some caching servers will not cache a URL with a query string
  • The mtime of the file would be different across a web cluster, so you would have conflicting URLs and the cache wouldn’t work as expected
With the Rails 3.1 Asset Pipeline the files are now named with a hash in their file name, so monkeys.jpg becomes monkeys-bec6c752b4e7fbfa9ee4b99b562a03ca.png.
This, like the previous technique, comes for free in terms of configuration in the application, how you reference an image etc*, however when you deploy there is a rake task you should run to generate these files, which is rake assets:precompile.
So, how do you make this happen all by magic? Well I use Capistrano for deployment, so all I really need to do it make it call the rake tasks after deploying. You can easily do the same by adding the following code to the bottom of your deploy.rb file:
namespace :assets do
  task :precompile, :roles => :web do
    run "cd #{current_path} && RAILS_ENV=production bundle exec rake assets:precompile"
  end

  task :cleanup, :roles => :web do
    run "cd #{current_path} && RAILS_ENV=production bundle exec rake assets:clean"
  end
end

after :deploy, "assets:precompile"

There is also a cleanup task included to get rid of any hanging around assets which aren’t being used any more which you can run by calling cap assets:cleanup.

Hope this helps.

* There is one caveat, and that is with images referenced in CSS – if you are using SASS you can use image-url(...) which will output a url(...) directive with the correct URL, however in plain old CSS you should use url('<%= asset_path(...) %>'); and name the file with the .erb prefix to be preprocessed.