Discussion Topics

« Return to Tips & Tricks

ENV['RAILS_ASSET_ID'] - The Silent Killer

Joe

ENV['RAILS_ASSET_ID'] - The Silent Killer

I discovered this issue after working with rails for less than a month, but after various conversations I’ve had with various people, I think it’s important that I share this tip so that everyone can benefit from it.

Default Behavior with Perverse Side Effects

Rails default behavior has this set to nil, which is a serious performance issue on many levels if you have any traffic your site at all. Even if you have the servers and/or bandwidth to handle it, some of your users will see your site just crawl and crawl…

If you haven’t set to a constant value (or maybe your app revision?), then set to an empty string in your environment.rb, or you’ll be sorry:

My Recommended Solution

ENV["RAILS_ASSET_ID"] = ''   # Prevents numerous file stat() calls
                             # and client-side cache busting.

Why do we want to buck the trend?

Seriously, though, when I took the lead on the development of CollectiveX I happened to take a look at the static asset paths that rails was generating by default, and I was shocked to say the least:

# Example image path w/ default settings.
/images/icons/someicon.gif?123456789

Cache Busting Paths… by Default?!?

While this may reduce the bug reports that the rails core developers get from newbies that don’t realize that their images are being cached in the browser, it makes your app behave in a shocking manner which is nowhere near sufficiently documented.

Tens or Hundreds of File Stats on Each Request

If ENV['RAILS_ASSET_ID'] is unset or nil, then Rails will stat the target file to determine it’s mtime.

This will happen for every single static asset on your page, and every time the page is rendered.

URLs which prohibit HTTP caching by nature

Next, when the browser retrieves your page, it is actually prohibited from caching any of the images, by the HTTP spec, due to the GET parameter in the query string portion of the URL.

Some browsers will disobey this part of the spec, others will not.

This is the exact same technique recommended to users having issues with Internet Explorer caching their AJAX responses. This is a cache busting technique.

What You Should be Doing Instead

  1. Turn off the asset ID:
    ENV["RAILS_ASSET_ID"] = ''  # In your environment.rb
  2. Set caching directives in your webserver’s configuration files.

  3. Use an asset packager:

    Asset Packager
    We use a heavily modified version at CollectiveX, which I’ll post here soon

    Bundle-Fu
    Never tried it

  4. Use more aggressive caching directives for assets which are packaged. Now you control when the client-side cache gets busted, because the URL changes only when the revision has changed.

If You’re Still Not Sure What This is All About

Just ask me, I won’t mind. :)

Replies to this Topic

Joe

In addition to all of this, if you serve content from more than one host name and you use both HTTP and HTTPS on your site, you should also take a look at asset_domain as an alternative to the non production-ready “asset_host” which ships with Rails.

The stat calls are actually cached in ruby code.

Joe

Stat calls are not the concern here.

Nothing in the HTTP spec prohibits caching if a URL contains a query string, that is just plain wrong.

You have misunderstood the whole point of Rails adding a timestamped or RAILS_ASSET_ID stamped querystring, it is to allow you to set a very long expires time and then force the browser to refetch cached content when it changes on the server.

If you are concerned about checking the mtime for each file then set RAILS_ASSET_ID to a value, NOT the empty string, then change it every time that you deploy.

Post Reply

You must be a member of this Groupsite in order to post a reply to this topic.
Click here to join this group.