While converting Clearance to a Rails engine was easy, once we were there, we found it wasn’t Valhalla.

We fixed the bugs while using the engine internally on a few apps. Here are the lessons we learned. Keep them in mind if you’re thinking of writing your own engine.
Routes precedence
As developers, we want routes in our app to take precedence over routes in the engine. That is not the default behavior.
To get around that, we came up with this hack. (credit to Nick Quaranto, a.k.a. qrush a.k.a. Internbot)
class ActionController::Routing::RouteSet
def load_routes_with_clearance!
clearance_routes = File.join(File.dirname(__FILE__),
*%w[.. config clearance_routes.rb])
unless configuration_files.include? clearance_routes
add_configuration_file(clearance_routes)
end
load_routes_without_clearance!
end
alias_method_chain :load_routes!, :clearance
end
Rather than using the Rails engine convention of naming the routes file
vendor/gems/clearance/config/routes.rb, we named it
vendor/gems/clearance/config/clearance_routes.rb so it won’t be automatically
loaded. Then we alias_method_chain around some ActionController internals.
Ugly stuff, but effective and solved a blocker for releasing as an engine.
Cached classes in development
In development, all your classes are constantly reloaded. This makes sense for your app, but not for your engine classes or modules.
We added
unloadable
to our Clearance module to fix this. Again, credit goes to Nick.
class Clearance::SessionsController < ApplicationController
unloadable
end
If you see errors like the following, you might consider a similar approach.
has been removed from the module tree but is still active
Namespacing controllers
We decided namespacing controllers was a good convention for our engine.
When we need to override something in the engine, this gives us clear routes separation…
# in the engine
ActionController::Routing::Routes.draw do |map|
map.resources :users, :controller => 'clearance/users' do |users|
users.resource :password,
:controller => 'clearance/passwords',
:only => [:create, :edit, :update]
end
# in the app
ActionController::Routing::Routes.draw do |map|
map.resources :users
end
… and clean subclassing:
class UsersController < Clearance::UsersController
def edit
...
end
end
Helper inclusion
Tammer has also recently been extracting the announcement code from
Hoptoad into an engine. He found that helper :all in
the controller doesn’t find engine helpers.
Within the engine’s init.rb, he hooked his engine’s AnnouncementsHelper into
the app’s ApplicationHelper like so:
config.to_prepare do
ApplicationController.helper(AnnouncementsHelper)
end
Note that any code that extends classes from the application (such as
ApplicationController) must be wrapped in a to_prepare block.
This is because ApplicationController gets reloaded before each request during
development. Without this block, only the first request would see the
AnnouncementsHelper methods.