Obscure Rails 3.1 asset pipeline feature messes with my head

For some time, I have been in the habit of appending a datestamp to my image assets whenever I update them. This is a low-tech, reliable cache-buster. For example, if I add a new icon to the sprite image “app-icons-20110901.png” (last edited 1 September 2011), I would change the name to “app-icons-20110909.png“, and change the matching CSS from

.test {
    background-image:url(/images/sprites/app-icons-20110901.png);
}

to

.test {
    background-image:url(/images/sprites/app-icons-20110909.png);
}

By changing the name of the file, I can guarantee that as soon as a browser gets the new CSS, there is no risk of it re-using an old version of the sprite file from cache. This works great on static sites that are updated rarely, and on sites where you haven’t gone to the trouble of implementing a more sophisticated system of (image) asset fingerprinting.

Rails 3.1 comes with fingerprinting baked in as part the new asset pipeline. Unfortunately, the asset pipelining breaks in the presence of my manual fingerprinting efforts. Rails refuses to serve up an image asset whose file name ends in a dash followed by more than 6 digits:

  • /app/assets/images/app-icons-2011.png is fine
  • /app/assets/images/app-icons-201109.png is fine
  • /app/assets/images/app-icons-2011090.png doesn’t work
  • /app/assets/images/app-icons-20110909.png doesn’t work

The error reported is a straightforward Routing Error:

No route matches [GET] "/assets/app-icons-20110909.png"

So code like this in a stylesheet will not work:

/* application.css.erb */
.test {
    background-image:url(<%= asset_path 'sprites/app-icons-20110909.png' %>);
}

(Also, running bundle exec rake assets:precompile will not generate a matching MD5 fingerprinted image under /public for the affected file.)

I haven’t gone into the source code to find out exactly where this happening (I think this all goes on under the hood in Sprockets rather than in Rails itself) but as the old joke goes, the solution is pretty simple:

Doctor, doctor! It hurts when I do this!

Well, stop doing that, then.

If you’re doing Rails 3.1, just let it take care of the fingerprinting, and everything will be fine.

Further reading: