Dec 13 2007

Rails Asset Cache
5

As a follow up to my article on Minifying Your Rails Javascript, let’s take a look at a new feature in Rails 2.0 that makes packaging your assets into a single file much easier.

Enabling Cache

We use asset helpers such as javascript_include_tag and stylesheet_link_tag in our layouts to include external Javascript and CSS files. One benefit of using these helpers is the ability to cache these resources. Asset cache is turned on when the perform_caching configuration option is set to true.

Rails applications default to having caching disabled during development, and enabled in production. We can change this in config/environments/development.rb to test out caching during development.

config.action_controller.perform_caching = true

Caching Assets

We enable asset caching in our applications using the :cache option in our helpers. We can cache Javascript files by doing the following:

<%= javascript_include_tag "prototype", "application", "effects",
                           :cache => "cache/all" %>

When caching is disabled, Rails will generate the normal references to these resources.

<script src="/javascripts/prototype.js?1197321216" type="text/javascript"></script>
<script src="/javascripts/application.js?1197321216" type="text/javascript"></script>
<script src="/javascripts/effects.js?1197321216" type="text/javascript"></script>

However when caching is enabled, Rails will generate a single external Javascript file in the location we specified. It will then reference this file instead of the original source files.

<script src="/javascripts/cache/all.js" type="text/javascript"></script>

As you can see in the above example, we’re going to store our asset cache in subdirectories named cache/. This makes it easier to clear out the cache later on. Caching external CSS files works similar to the Javascript example:

<%= stylesheet_link_tag "typography", "layout", "color",
                        :cache => "cache/all" %>

Clearing Cache

Rails comes with some useful built-in tasks for clearing out temporary files under the tmp: rake namespace. Rails does not come with a built-in task for clearing out the asset cache. We’ll add this ourselves by adding a new rake task named rake tmp:assets:clear. Create a new file in your Rails application named at lib/tasks/tmp.rake, and add the following code.

namespace :tmp do
  namespace :assets do 
    desc "Clears javascripts/cache and stylesheets/cache"
    task :clear => :environment do      
      FileUtils.rm(Dir['public/javascripts/cache/[^.]*'])
      FileUtils.rm(Dir['public/stylesheets/cache/[^.]*'])
    end
  end
end

The custom tmp:assets:clear task we added removes all files from both the javascripts/cache/ and stylesheets/cache/ directories. Let’s give it a whirl:

$> rake tmp:assets:clear

Wrap Up

Using asset cache can significantly reduce the number of requests sent to the server for external CSS and Javascript files. Along with a good gzip strategy, this is an essential feature when working with large multi-file Javascript libraries.

For additional performance increases using asset helpers, check out Chad Fowler’s write-up of Distributed Asset Hosts.

5 comments

  • comment by Akhil Bansal 16 May 08

    Just wondering if it bundle all JS into one in same order as they specified.

  • comment by roger 2 Jun 08

    does this do minifying, as well?

  • comment by derek 2 Jun 08

    Akhil: It should bundle the js in the order they are specified

    roger: It does not minify the results. I mention in an update to my minifying javscript article that:

    “Prototype doesn’t actively support a specific packing strategy for various reasons, and patches submitted for making the code pass something like JSLint are likely to be ignored. Reasons for this, and some other strategies on reducing filesize of the library are discussed in Packing Prototype.”

    Based on this, i would recommend against minifying your javascript and instead using something such as gzip compression.

  • comment by ron 24 Jun 08

    what happen when i change my js, how do i make sure the user’s browser load the new version? do i need to change the name of the cached file?

    does’t this method adds a timestamp in the file’s name?

  • comment by Lucas 8 Nov 08

    I have a pain in the ass….. i have a rails 2 application and i set the file_store caching… however, i don’t see any files in my cache folder… why?

    Besides, i did your solution to clearing my cached assets and didn’t work because i have nothing in my public/style../cache folder…

    I’m desperate… thanks in advance.

Sorry, the comment form is closed at this time.