Now that you know more about the different use cases of modularity, let’s talk about how we can create modular applications with Ruby on Rails. Rails comes with a nice feature known as engines that let you create mini Rails applications. You can then easily use these engines as gems inside a regular application. Let’s talk about this engines
thing!
This is the second article in the Modular Rails series. Here are the other posts:
- Modular Rails: Introduction
- Modular Rails: Use Cases
- Modular Rails: The Engines
- Modular Rails: Architectures
- Modular Rails: Create a modular app
- Modular Rails: F.A.Q
Quick overview of Rails engines
As said earlier, Engines are small Rails applications that can be used to add functionalities to the application hosting them. The class defining a Ruby on Rails application is Rails::Application
which actually inherits a lot of its behavior from Rails::Engine
, the class defining an engine. We can say that a regular Rails application is simply an engine with more features.
Engines are also close to Plugins. Plugins are not really used anymore since Rails 3.0 but the command to generate an engine is actually the same used to generate a plugin.
The command looks like this:
rails plugin new my_module --mountable
Mounting an engine
An engine cannot live on its own so you need to mount it inside a regular Ruby on Rails application. Don’t worry, it’s super simple! All you have to do is this:
Rails.application.routes.draw do
mount SuperEngine::Engine, at: '/', as: 'super_engine'
end
In this example, we mounted the SuperEngine engine at the root of your application. That’s what you want if your application is logicless. However, if your Rails application has some content, you probably want to do the following:
Rails.application.routes.draw do
mount Forum::Engine, at: '/forum', as: 'forum'
end
Now the Forum engine can be accessed by going to /forum
but the root (/) will ignore the engine and find the root path in the mother application.
Namespacing
Engines can and should be namespaced. That means that 2 models with the same name, one in an engine and one in the host application, won’t clash. When generating an engine, everything is automatically namespaced: tables, models, controllers. If you generate an engine named Core and a User
model, the User table will be core_users
and your model will be Core::User
.
As you will be able to read it in the book, I recommend going one step further and adding another level of namespacing. If you plan to create a lot of engines and want to avoid any future conflict, you can just namespace with your project or company name at the first level and then use the engine name as the second namespace.
Instead of having:
module MyModule
class User < ActiveRecord::Base
end
end
module Global
module MyModule
Class User < Activerecord::Base
end
end
end
With this system, you can keep your engines organized under a common namespace. You can rest assured that you won’t get any problem when adding external engines to your application.
A special thanks to James Adam, Piotr Sarnacki, the Rails Core Team, and a number of other people for their awesome work on the Rails Engines!
Engines in the wild!
Even if you’ve just discovered engines, you’ve probably been using them for a while. One of the most famous authentication gem is actually an engine. Of course, I’m talking about Devise! Basically, any gem that will provide you with some Rails-related component such as migrations, controllers, views or models is usually an engine packaged as a gem.
There are also some open source modular applications such as Spree. Spree is an open source e-commerce solution built as a modular application with Ruby on Rails. With their solution, it’s possible to either use all the modules or just pick the ones you need! Awesome!
Want to learn more?
You can continue reading about modularity with this article about modular architectures.
You can also checkout the book I wrote about modular applications : Modular Rails.
Don’t hesitate to subscribe to my newsletter in the form below or on the book website to receive a free sample of the book.