Notes on Using Jammit with Rails
I spent some time this weekend wiring up a new Rails application to use Jammit for asset caching. So far I'm quite happy with the results; it offers a sophisticated set of asset caching strategies (indeed, we're not even making use of them all yet) and does its compression on the client side during the deployment process. For those who aren't complete experts in all things sysadmin, a few notes on making this work:
1) If you're using the rails_xss plugin (or Rails 3), you'll need to make sure it doesn't try to escape the HTML generated by the Jammit helpers. You do this by wrapping all calls to those helpers in the
raw
helper:
<%= raw include_stylesheets(:common, :media => 'all') %>
<%= raw include_javascripts(:common) %>
2) For deployment, I'm using this chunk of code in my Capistrano recipe (hat-tip to kpumuk whose gist I started from):
namespace :deploy do
desc 'Bundle and minify the JS and CSS files'
task :precache_assets, :roles => :app do
root_path = File.expand_path(File.dirname(__FILE__) + '/..')
assets_path = "#{root_path}/public/assets"
gem_path = ENV['GEM_PATH']
run_locally "#{gem_path}/bin/jammit"
top.upload assets_path, "#{current_release}/public", :via => :scp, :recursive => true
end
end
after 'deploy:symlink', 'deploy:precache_assets'
This will build the assets locally and then upload them. You'll want to add public/assets
to your .gitignore
file.
3) You should have mod_expires loaded in Apache to handle far-future expiration dates for asset access. If this is missing, you'll get an error when you try to load a configuration file that includes the ExpiresDefault
directive. On Debian, this is as simple as moving expires.load
from /etc/apache2/mods-available
to /etc/apache2/mods-enabled
(which is what a2enmod
does). If you're using some other flavor of OS, try this article for instructions. OS X includes mod_expires by default.
4) The Passenger documentation says flat out that MultiViews is incompatible with Passenger. So far, I haven't found any problem enabling MultiViews just on the assets directory, though, probably because it doesn't go through Passenger.
5) Here's a vhosts entry that sets things up for a Jammit-enabled application:
<VirtualHost *:80>
ServerName myapp.com
RailsEnv production
DocumentRoot /u/apps/myapp/public
<Directory "/u/apps/myapp/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory /u/apps/myapp/public/assets>
Options MultiViews
ExpiresDefault "access plus 1 year"
</Directory>
</VirtualHost>