Asset Magic Tricks
What if you didn’t have to copy over assets between projects every time you wanted consistency? I learned a neat little trick that lets you package assets away into a Gem that can be bundled with any number of Rails applications.
I first realized this was possible when I tried the twitter-bootstrap-rails
gem. This gem lets you use Twitter’s Bootstrap without needing to copy over or generate any files into your assets directory. Updating bootstrap across applications becomes as simple as updating the gem version. The files appear to be magically loaded and are somehow found when requiring them from a manifest file.
The way this works is with Rails Engines. Engines are essentially small Rails applications that get loaded within (and sometimes mounted to) your main application. Making your gem a Rails Engine is quite simple.
Creating the Gem
As an example, we’ll write a simple gem that will contain some styles to make h1
tags look nicer. We’ll call it pretty_h1
.
First, start off by generating the new gem:
$ bundle gem pretty_h1
To set up your gem as an Engine, you’ll need to do two things. First, create the file /lib/pretty_h1/engine.rb
and fill it with the following:
module PrettyH1
class Engine < ::Rails::Engine
end
end
Second, you need to require the file we just created by adding require 'pretty_h1/engine'
to /lib/pretty_h1.rb
.
Now that the gem has been set up to behave like a Rails Engine, it can take advantage of the fact that in an Engine, the /vendor
directory is loaded automatically. Lets add a stylesheet in /vendor/assets/stylesheets/pretty_h1.css
.
h1 {
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: 48px;
font-weight: normal;
}
The last step before we can use our new gem is to complete the Gemspec. Don’t forget to add Rails as a dependency by adding spec.add_dependency 'rails', '>= 3.1'
to your gemspec.
Using the Gem
To use the gem we’ll need to add it to a Rails application’s Gemfile
. Either releasing the gem and get from RubyGems or use path
to specify the path to the gem on the filesystem. Once it’s in our Gemfile
, bundle it by running:
$ bundle install
Our app now has access to all the assets in our gem’s /vendor/assets/
directory! We can require the pretty_h1.css
file from our Rails application’s application.css
by adding a require in the manifest section of application.css
:
*= require 'pretty_h1'
After refreshing the page, you’ll notice that the style from our pretty_h1
gem has been applied to the h1
tags.
More Magic
This magic doesn’t stop at assets. Rails Engines are powerful and let you add a lot of functionality to an application. A great example of Rails Engines being put to good use is plataformatec’s devise.
Devise makes use of an Engine’s ability to add a gem’s files to the load path so that they become available to the application without copying them over. More specifically, devise adds models, controllers, and views to the load path. This allows developers to make use of ready-made chunks of applications in their own apps.