Find file
Fetching contributors…
Cannot retrieve contributors at this time
189 lines (137 sloc) 7.7 KB
Ruby on Rails plugin 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 (explained below).
The default configuration used by the plugin is based on guidelines given by
Google Page Speed:
The plugin alters AssetTagHelper so that all the relevant helper methods (image_path,
image_tag, stylesheet_link_tag, etc.) all generate the correct fingerprinted URLs.
Plugin can also be configured/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 you can.
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/js bundles)
In all 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.
This plugin is in use on
Rails Versions
Tested with Rails 2.2.3 though there's a good chance it'll work with earlier
and newer versions with little or no modification.
Getting started
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
Including both of these above settings would give you the same behaviour that
comes with Rails out-of-the-box.
Write your own fingerprinters and path_rewriters
If you need to it is simple to write your own fingerprinters and path_rewriters
and configure them in the initializer script. View source code to see how this
can be done.
Using file_name path rewriting
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 option and a symlink option.
You can use both methods for different environments, for example I use the
server rewrite option in development to save muddying my dev environment with
lots of symlinks, but go with the symlink option in production so I can
use Passenger's high performance option (which requires that Apache Rewrite is
not used).
Option 1 - Server Rewrite
If you decide to use the Server Rewrite method, add this line to the initializer
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.
Option 2 - Generate symlinks
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 via a rake task.
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 favicon.ico
tends to be.
Using the rake task is recommended to save the overhead of generating the symlinks
on the fly during user requests in a production environment.
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.
If you're trying the symlink option out and afterward want to remove only
symlinks from the public directory, you can use this command in your app root
shell> find public/ -type l -exec rm -i {} \;
Remove the -i option if you don't want to be prompted to delete each symbolic
link. Be careful using this as you may delete symlinks you did not want to.
If for some reason you don't want to use the fingerprinted path for some of your assets,
you can edit the excludes configuration:
AssetFingerprint.excludes = ['^bootstrap'] # defaults to an empty array
This is a list of regular expression to check. If any matches your asset's path,
then that file will not be fingeprinted.
More projects at
Copyright (c) 2010 Eliot Sykes, released under the MIT license