Skip to content

Asset Fingerprint Plugin for Ruby on Rails - allows you to use md5 or timestamps in query string or in asset filenames as suggested by Google Page Speed

License

Notifications You must be signed in to change notification settings

evanworley/asset_fingerprint

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AssetFingerprint
================
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: http://code.google.com/speed/page-speed/docs/caching.html

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 MissedConnections.com.

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
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]

-OR-

# 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 generated symlinks are in the same directory as the asset they
link to. You can use the symlink_output_dir property to specify where the
symlinks will be generated (a directory under public/). For example the following
configuration would result in public/images/foo.png having a fingerprinted symlink
public/fingerprinted_assets/images/foo-fp-77f3c63bea170a3b5ba5d598364efcdb.png.
This option can be useful in your development enviornment, in conjunction with
source control ignore properties (such as svn:ignore).

# Put this in config/initializers/asset_fingerprint.rb
AssetFingerprint.symlink_output_dir = "fingerprinted_assets"

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.

Tips
====
--
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. 


CONTRIBUTORS:
Eliot Sykes http://github.com/eliotsykes
Evan Worley http://github.com/evanworley

==============================================================
More projects at http://blog.eliotsykes.com/my-projects/
==============================================================
Copyright (c) 2010 Eliot Sykes, released under the MIT license

About

Asset Fingerprint Plugin for Ruby on Rails - allows you to use md5 or timestamps in query string or in asset filenames as suggested by Google Page Speed

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 100.0%