Brighter Planet's blog
Here at Brighter Planet we run several production Rails 3 apps, including the emission estimates service, the climate data service, and our keyserver. As the person reponsible for much of our recent front-end work, I wasn’t really looking forward to maintaining a half-dozen different versions of what is mostly the same layout. I wanted to DRY the situation up. What I really wanted was to put all the shared stuff into a gem that I could require from all of our apps that would just sort of insinuate itself into all the right places.
Luckily Rails 3 makes this possible, after a fashion. The key trick is giving your plugin a Railtie, which isn’t documented very well yet–this gist from Jose Valim is the best I could find.
To get started just add a file in
railtie.rb and require it from the main
module BrighterPlanetLayout class Railtie < Rails::Railtie end end
Because it inherits from Rails::Railtie, you don’t have to “declare” the Railtie–Rails automatically keeps track of it and calls the right parts when they’re needed.
The easy part is telling Rails to add your gem’s view path to the app’s view path:
module BrighterPlanetLayout class Railtie < Rails::Railtie initializer 'brighter_planet_layout.add_paths' do |app| app.paths.app.views.push BrighterPlanetLayout.view_path end end end
Telling ApplicationController to use the layout in your gem’s view path as the default is a little tricker–you have to use a
module BrighterPlanetLayout class Railtie < Rails::Railtie # ... config.to_prepare do ApplicationController.layout 'brighter_planet' end end end
It turns out the hardest part is hooking Rails up to your gem’s static asset files–stylesheets, images, fonts, etc. For that we add another instance of
ActionDispatch::Static to the Rack middleware stack:
module BrighterPlanetLayout class Railtie < Rails::Railtie config.app_middleware.use '::ActionDispatch::Static', BrighterPlanetLayout.public_path # ... end end
This is a fine solution in the development environment, but it’s too slow for production–your webserver has to fire up Rails just to push an image binary, for example. So in production we just copy static files to the app’s
module BrighterPlanetLayout class Railtie < Rails::Railtie if BrighterPlanetLayout.serve_static_files_using_rack? # "if in development environment" config.app_middleware.use '::ActionDispatch::Static', BrighterPlanetLayout.public_path end initializer 'brighter_planet_layout.copy_static_files_to_web_server_document_root' do if BrighterPlanetLayout.copy_static_files? # "if in production" BrighterPlanetLayout.copy_static_files_to_web_server_document_root end end # ... end end
And that’s it. Check out the gem source for details on the folder structure and for additional tricks like loading shared helpers. Next time: how to use this shared layout with Jekyll.