Caching assets in a Rails 3 app on Heroku

In Rails apps, you often have multiple css and javascript files. If you’re using the “javascript_include_tag” and/or “stylesheet_link_tag” helpers, you can let Rails automatically package multiple files into a single file by using the “:cache => true” option. I’m sure you’re already aware of this, but if not, you can read more about it here.

A problem arises when trying to deploy an app using this technique to Heroku due to their read-only filesystem constraint. If you’re familiar with Yahoo’s Best Practices for Speeding Up Your Web Site and related YSlow tool, you know that caching your assets is an important part of having a speedy site.

There are a lot of possible solutions to this problem hanging around, but none of them seemed 100% ideal for my situation. So, I asked if there is a preferred method of caching/packaging assets in a Rails 3 app on Heroku in the Heroku Google Group. Nothing much came up, so I did a bit of Googling and came across this Stack Overflow page that pointed me in the right direction.

I’ve written a couple of small rake tasks that have been working quite well for me. The first is the “rake deploy” task. So, now I use “rake deploy” instead of “git push heroku master” when I want to deploy to Heroku. This caches my assets, pushed to github, deploys to heroku, and notifies hoptoad about the deploy.

But the “rake cache_assets” task is what we’re really interested in here. This leverages the built-in functionality of Rails to cache your assets, so it works exactly as you’d expect. It’ll create the “all.js” and “all.css” automatically, because I’m using the “:cache => true” option in my helpers. It’ll commit those files (if they’ve been changed) and then when I set “config.action_controller.perform_caching = true” in my “config/environments/production.rb” file, my app will use the cached files automatically.

This is a great first step, but there’s still more that can be done. As Heroku’s David Dollar pointed out in the Google Group, one could package these assets up and upload them to S3, using CloudFront as a CDN, and telling Rails to use that as your asset host. I’ve talked about CloudFront before, and I’ve had nothing but positive experiences with it, so I might try this in the future (uploading to S3 with fog, of course). If you’re interested in collaborating on this, please drop me a line.

Published by

Trevor Turk

A chess-playing machine of the late 18th century, promoted as an automaton but later proved a hoax.

14 thoughts on “Caching assets in a Rails 3 app on Heroku”

  1. Yeah, that's another smart thing to do — I was thinking that I'd work on moving the assets to CloudFront and then set far future expires on there first, though.

  2. On my blog, I use my sinatra extension sinatra-bundles to handle JS and CSS combination/compression and then I stuff Amazon Cloudfront in front of that stuff too. Works pretty slick.

  3. Hi Trevor,

    I suggesting tightening it up a tad by checking for git diff-index HEAD with ONLY the 2 all.js and all.css files and also ONLY committing those two files. You may have uncommitted changes that you dont want to deploy as yet.

    Also "pushing to github" might be better read as "pushing to origin" (but thats just for us copying your stuff and not pushing to github).

    Thanks!

    Aditya

  4. I want to implement this too, but am getting stumped on the line:

    session.get('/')

    If I output the result it's '500', so clearly something is wrong. But what I can't tell. Browsing to the website on localhost works (and generates the desired cache files). I'm at a loss as to what the problem is or how to even get a meaningful error message from .get().

    Any advice?

Comments are closed.