Asset Fingerprint is a Ruby on Rails plugin (supports Rails versions 2.2.x & 2.3.x, for Rails 3+ see Rails Version Support) to fingerprint asset files using md5 checksum (or timestamp or anything else you like) in file names to improve cacheability compared to the default Rails asset caching strategy.
So, instead of asset paths like /images/logo.png?1234567890
you can have
fingerprinted asset paths like
/images/logo-fp-839b180ff39a24f8d6e0ee70e4c40fed.png
with no query string.
The server knows how to handle the fingerprinted asset paths using rewrite rules or symlinks, as explained in file_name path rewriting.
At time of writing, the default configuration used by the plugin is based on guidelines given at Google Page Speed.
The plugin alters AssetTagHelper
so the relevant helper methods (image_path
,
image_tag
, stylesheet_link_tag
, etc.) generate the correct fingerprinted URLs.
Asset Fingerprint can also be customized in any other way, for example if you wanted to use the default Rails asset caching strategy of putting file timestamps in the query string, then you can, however…
File timestamps are not recommended as fingerprints as these are often inconsistent between deployments when a file has not changed. This means your app may not take full advantage of asset caching. Reasons for timestamp inconsistency include:
- Multiple app servers checking out files at different times
- Git does not preserve file timestamps (it really doesn't)
- Subversion not configured to preserve file timestamps
- Generated asset files (e.g. compressed css and js bundles)
In all of these cases the md5 checksum does not change unless the file contents have changed, so using an asset file's md5 checksum as its fingerprint is often a better option than a file timestamp.
Putting fingerprints in the query string is also not recommended as some caching proxies are allegedly incorrectly configured to ignore query string parameters. File name fingerprinting gets around this problem.
- Tested with Rails 2.2. & 2.3.x though there is a chance it will work with earlier versions.
- For Rails 3.1, use Rails' own asset fingerprinting provided by the asset pipeline
- For Rails 3.0, take a look at https://github.com/polleverywhere/asset_fingerprinter
-
Install the plugin at
vendor/plugins/asset_fingerprint
in your app. -
Then you must create a
config/initializers/asset_fingerprint.rb
file and put the following require statement in it:require 'asset_fingerprint/asset_tag_helper'
-
By default, the plugin will give your app asset paths with maximum cacheability, i.e. using md5 fingerprints as part of the asset file name, however if you do not want this, then you can change it. For example if you want to use timestamp fingerprints instead of md5 fingerprints, or you want to put the fingerprint in the query string instead of the file name, then you can add one or both these lines to the initializer script we just created:
AssetFingerprint.fingerprinter = :timestamp # default is :md5
AssetFingerprint.path_rewriter = :query_string # default is :file_name
If you need to, it is simple to write your own fingerprinters and path_rewriters and configure them in the initializer script. View the source to see how this can be done.
The :file_name
path rewriter is used by default and changes the file name of
the asset paths generated by rails helpers such as image_tag
, image_path
,
stylesheet_link_tag
, etc.
Your app will need to know which asset file to serve for a given rewritten file path as the rewritten paths do not correspond to a real file.
Luckily getting your app to do this is simple in most cases, two options are presented below, a Server Rewrite and a Generate Symlinks option.
You can use both methods for different environments within the same app. For example, I've previously used the server rewrite option in development to save muddying my dev environment with lots of symlinks, and in the same app used the symlink option in production so I could use Passenger's high performance option (which required that Apache Rewrite is not used).
If you decide to use the Server Rewrite method, add this line to the initializer script:
AssetFingerprint.asset_files_served_by = :server_rewrite
Then, assuming you are using Apache, add one of these rewrite rules to get it to serve the correct asset file for a fingerprinted path:
# For md5 fingerprints
RewriteRule ^(.+)-fp-[0-9a-z]{32}(.*)$ $1$2 [QSA,PT,L]
# For timestamp fingerprints
# (you should check that the timestamps returned by your production operating
# system are 10 digits long. If they are not, change the {10} in the regex
# below to the correct length.)
RewriteRule ^(.+)-fp-[0-9]{10}(.*)$ $1$2 [QSA,PT,L]
If you're not using Apache, then adapt the rules above for your server.
P.S. User-submitted rewrite rule for nginx rewrite "^(.+)-fp-[0-9a-z]{32}(.*)" $1$2 last;
This option creates a symlink for each asset file, where the symlink is the
rewritten filename, e.g. the asset file images/logo.png
would get a symlink
like images/logo-fp-1234567890.png
pointing to it.
The symlink option is recommended if you think symlinks will give you better performance than rewrite rules.
By default, the plugin generates symlinks on-the-fly, however you can generate all the symlinks ahead of time at deployment using rake:
rake asset_fingerprint:symlinks:generate
If you use this rake task you'll want to stop symlinks from being generated on-the-fly. Add this setting to your initializer script:
AssetFingerprint.symlink_on_the_fly = false
Call the rake task like so (you may want to do this with capistrano):
rake asset_fingerprint:symlinks:generate RAILS_ENV=the_env
If your app has asset files or directories in public/
that are not any of
these defaults: ['favicon.ico', 'images', 'javascripts', 'stylesheets']
then add this setting to the initializer script and customize as needed:
AssetFingerprint.asset_paths = ['my-custom-image.png', 'my-custom-dir', 'favicon.ico', 'images', 'javascripts', 'stylesheets']
The AssetFingerprint.asset_paths
setting is used by the rake task to decide
which files to symlink. If you specify directories, it will search them
recursively for asset files symlinking as it goes. You only need to specify
exact file names if they are immediate children of public/
, like public/favicon.ico
.
Using the rake task is recommended to save the overhead of generating the symlinks on the fly during user requests in a production environment.
- To remove the generated symlinks call
rake asset_fingerprint:symlinks:purge
- By default the plugin will cause symlinks to be generated in your development environment
(take care not to commit the symlinks to your repository) until you set
AssetFingerprint.symlink_on_the_fly
to false.
- Eliot Sykes http://github.com/eliotsykes
- Evan Worley http://github.com/evanworley
- Joe Van Dyk http://github.com/joevandyk
Copyright (c) 2010-2013 Eliot Sykes, released under the MIT license