The Problem: Modularizing and Reusing Code

In large Ruby on Rails applications, keeping the codebase modular and manageable is a challenge. Often, multiple applications share functionality like authentication, admin dashboards, or payment systems. Copy-pasting code between apps leads to maintenance headaches and inconsistency.

Rails Engines solve this by providing a way to encapsulate features or functionality into reusable, self-contained modules.

What is a Rails Engine?

A Rails Engine is a mini Rails application that can be mounted inside another application. It has its own models, views, controllers, and even routes. Engines are ideal for creating reusable components shared across multiple applications.

When to Use Rails Engines

  1. Shared Functionality: When multiple applications need the same features, such as authentication or reporting.
  2. Modularity: To separate large parts of an application into smaller, independent modules.
  3. Reusable Gems: When building functionality to distribute as a Ruby gem.

Setting Up a Simple Rails Engine

Step 1: Create a New Engine

Run the following command to generate a Rails Engine:

rails plugin new my_engine --mountable

The --mountable option creates a fully isolated engine with its own namespace.

Step 2: Directory Structure

The engine’s structure is similar to a Rails application but scoped to the engine:

my_engine/
├── app/
│   ├── controllers/
│   ├── models/
│   ├── views/
├── config/
│   ├── routes.rb
├── lib/
│   ├── my_engine/
│   │   ├── engine.rb
│   ├── my_engine.rb

Step 3: Configure the Engine

Edit lib/my_engine/engine.rb to define your engine:

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

The isolate_namespace ensures that all models, controllers, and routes are scoped under the MyEngine namespace.

Step 4: Add Routes

Define routes in config/routes.rb:

MyEngine::Engine.routes.draw do
  resources :posts
end

Step 5: Mount the Engine

In the host application’s config/routes.rb, mount the engine:

Rails.application.routes.draw do
  mount MyEngine::Engine => "/my_engine"
end

Step 6: Create a Controller

Add a controller in app/controllers/my_engine/posts_controller.rb:

module MyEngine
  class PostsController < ApplicationController
    def index
      render plain: "Welcome to MyEngine!"
    end
  end
end

Step 7: Use the Engine

Start the Rails server and navigate to /my_engine/posts in the browser.