Dec 20 2012

Intro to Rails Engines

I have recently been hearing quite a bit about people using Rails engines. I was intrigued about how they are used and how they integrate into a Rails application, and I soon got a chance to satisfy my curiosity by working on a couple projects that used these engines. Here I will talk a little about what Rails engines are used for and how they are integrated into a Rails application.

What’s a Rails Engine?

So the first question you may be asking is, what the heck is a Rails engine, anyway? In short, it allows you to wrap up a Rails application or a subset of its functionality in a way that makes it easy to share it with other applications. This plug-and-play sort of functionality is quite similar to how Ruby gems work. In fact, prior to Rails 3.0, all Ruby gems automatically behaved as engines, and since Rails 3.0 all Rails applications are just engines. And just like a Rails application, a Rails engine is also a Railtie, so it has access to rake tasks and generators that can be used in the engine. Since Rails 3.0 has come out, if you want a gem to automatically behave as a Rails engine, you have to define an engine somewhere inside of the gem’s lib folder.

module MyEngine
     class Engine < Rails::Engine
     end
end

Types of Engines

When creating a Rails engine, there is one special thing to take note of, and this is the difference between a full engine and a mountable one. In a full engine, the parent application inherits all of the routes defined in the engine, so it is not necessary to define anything in parent/config/routes.rb. Simply specifying the Engine in the gem file of the parent application is enough for it to have access to all of the engines models, controllers, routes, etc. For a mountable engine, its namespace is isolated by default:

module MyEngine
     class Engine < Rails::Engine
          isolate_namespace MyEngine
     end
end

The routes of the engines are namespaces and it needs to be mounted in the parent app’s routes file to be used.

Parent::Application.routes.draw do
     mount MyEngine::Engine => '/engine', as: 'my_engine'
end

Helpers

Once you have your engine mounted inside of the parent application, some helpers are defined to help specify the routes. Inside of the parent app above there would he a helper named ‘my_engine’ that would allow you to access its routes like:

my_engine.root_url

From the engine, there is also a helper named ‘main_app’ that is defined that allows the engine to access the parent app’s routes.

MIGRATIONS AND SEEDING DATA

The parent application also needs to be able to install the migrations from the Rails engine. In order to copy over the migration files from the engine to the parent app you can run:

rake MyEngine:install:migrations

A migration would be skipped if one with the same name already exists within the application. Once the migrations have been copied over they can be loaded by running

rake db:migrate

If the engine has any seed data in the db/seeds.rb file it can be loaded by running

MyEngine::Engine.load_seed

tests

Finally, testing a Rails engine is a little different than just testing a Rails application. Inside of your test directory there is a dummy app, which is a Rails application that is used during testing. Your engine is automatically loaded into the dummy app and all of your tests are run from the dummy app’s environment. If you find it necessary, you can generate controllers, models or views in the dummy app to use while testing your engine. Special consideration must be taken when writing controller tests. Since the requests are going through the dummy application you need to be more specific when using the get, post, etc. methods. This is where the :use_route option comes in for in these methods.

get :index, use_route: :my_engine

This will perform a get request to the index action of the controller, but it specifies that you want to use the routes from my_engine to get there rather than those in the dummy application.

summary

Working with Rails engines has been an insightful experience and I have learned quite a bit about how they work. It is always fun to find out about new technologies to use, and I’m looking forward to continuing my exploration of Rails Engines and finding uses for them in my future projects.

Resources:
Rails Api
Railscast

3 Comments

  1. VIeenay

    good and simple explanation. Thanks

  2. Karan

    Clean explanation. Could you give us examples of the kind of engines have you written? Would an admin panel for a blog be extracted into an engine?

    Cheers!

    • Hey Karan, the rails engines that I have created so far encapsulate a few models and controllers that need to be shared across different applications. As I was learning about rails engines I made a couple different ones such as a blog engine and a to do list engine. I have also been playing around with an image/video uploader engine since I have used that functionality in several projects. Usually if you find yourself reimplementing the same functionality in several applications that is a good indicator that you could create an engine for that functionality.

      As for the admin panel I do think that would be good to have in an engine, but I would put it in the engine with the blog as well. This would remove any coupling between the engine and application because the admin panel wouldn’t rely on the application’s implementation of the blog. It would also mean that it would be easier to use in other apps since it doesn’t have external dependencies.

Leave a Comment

Join the discussion. Do not worry, your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>