Engines in Rails 2.3
Engines have been around Rails for years but it wasn’t until the recent 2.3 release that Rails officially supported Engines. So what is an Engine? An Engine is a Rails plugin with full MVC capabilities. In essence, that means your Engine has an app directory with helpers, controllers, models and views just like a standard Rails application. You add an engine to
vendor/plugins or through
config.gem in your application, just like a plugin, but additionally its app directory is effectively overlaid on top of your application’s app directory.
Let’s spelunk through the code:
def configure_engines if engines.any? add_engine_routing_configurations add_engine_controller_paths add_engine_view_paths end end def add_engine_routing_configurations engines.select(&:routed?).collect(&:routing_file).each do |routing_file| ActionController::Routing::Routes.add_configuration_file(routing_file) end end def add_engine_controller_paths ActionController::Routing.controller_paths += engines.collect(&:controller_path) end def add_engine_view_paths # reverse it such that the last engine can overwrite view paths from the first, like with routes paths = ActionView::PathSet.new(engines.collect(&:view_path).reverse) ActionController::Base.view_paths.concat(paths) ActionMailer::Base.view_paths.concat(paths) if configuration.frameworks.include?(:action_mailer) end
For each engine, we add any routes, any controllers and any views. Additionally, the directories within app will be added to the global LOAD_PATH, as with a normal application. Note that engines are processed in order exactly like plugins: alphabetically or based on the order they are listed in
There are some limitations you should be aware of:
- No migration support: while the engine can add models, it is not obvious how to manage any database structure needed by the engine. I would imagine the engine should use the install.rb hook to copy migrations to the app’s
- Like plugins, naming becomes a concern. An engine can have a User model but this will lead to problems with the 90% of Rails applications that have a model of the same name. You can put your models within a module but I’ve heard of problems when trying to mix Rails autoloading with modularized classes. As with plugins, be sure to err on the side of safety and use a unique name for your classes. I’m building an engine called Queso and it provides a model called QuesoSearch, which is unlikely to collide with application classes unless you are building an application for a Mexican cheese provider. :-)
So while Engines do have some limitations to be aware of, they do fill a valuable niche; engines provide a good framework for building full-stack generic application functionality. ActiveScaffold is one example of a Rails plugin that would be an excellent choice to rewrite as an Engine.