Motivation

diagram

Mounting applications within applications is a powerful technique, that allows developers to build highly scalable applications that are both cost effective and easy to maintain. Rails Engines give developers the power to transform a rails apps into ruby gems. Many popular ruby gems such as Device and Spree leverage rails engines to provide default custom views like login forms. Having a suite of rails engines has a ton of advantages and I would recommend refactoring large monolith apps into smaller engines.

Getting Started

As an example, i’m going to set up a blog that is made up of two component applications a blog_api and blog_core (the core application). I’m not going to do anything fancy, i’m just going to set up each component as separate rails apps and write a little extra code to make them “mountable”.

Blog API

Let’s start by, first, setting up the API.

rails new blog_api
cd blog_api
rails g scaffold posts title:string context:text
touch blog_api.gemspec

We also setup a gemspec; this allows us export our rails app as a ruby gem.

# ~/blog_api/blog_api.gemspec

$:.push File.expand_path("../lib", __FILE__)

Gem::Specification.new do |s|
  s.name        = "blog_api"
  s.version     = "0.0.1"
  s.authors     = ["Paul Serraino"]
  s.summary     = "testing out mounting apps"

  s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
  s.test_files = Dir["test/**/*"]

  s.add_dependency "rails", "~> 4.2.5.1"

  s.add_development_dependency "sqlite3"
end

Next, we’re going to setup the engine itself for our blog API.

# ~/blog_api

mkdir -p lib/engines/blog_api
touch lib/engines/blog_api/engine.rb
# ~/blog_api/lib/engines/blog_api/engine.rb

module BlogAPI
    class Engine < Rails::Engine
    end
end

Next, we’re going to add one more file

# ~/blog_api
touch lib/blog_api.rb
# ~/blog_api/lib/blog_api.rb

require 'engines/blog_api/engine'
module BlogAPI
end

That’s it, our blog API is now a ruby gem!

Blog Core

Now that we have our blog API gem we can include in our core application.

First, we need to setup our core app.

# ~/
rails new blog_core
cd blog_core

In our gem file we’re going to include the blog_api gem that we just created, using a relative path.

# ~/blog_core/Gemfile

gem 'blog_api', path: '../blog_api'

Next, we need to run the blog_api migrations with blog_core.

# ~/blog_core
rake blog_api_engine:install:migrations
rake db:migrate

And that’s it! We have successfully mounted our blog_api within blog_core.

So this was just a boilerplate example of using rails engines (just to get started). There are many ways of making your rails engine more robust, such as mounting an engine on a specific route or autosyncing database migrations. I’m not going to go into too much depth in optimizing a rails engine in this post , there are plenty of resources online to help you out, if you’re interested in doing that, but I will briefly cover autosyncing database migrations since it’s fairly easy to accomplish.

Syncing Migrations

Interestingly, Rails Engines inherent from Railties. Railties allow developers to hook into and extend the Rails initialization process. So we can write initializers in our blog_api engine and Rails will execute the initializers when the gem is required.

Let’s set up an initialization process to append the blog_api migrations to the migrations found in blog_core.

# ~/blog_api/lib/engines/blog_api/engine.rb

module BlogAPI
    class Engine < Rails::Engine

        initializer :append_migrations do |app|
            unless app.root.to_s.match(root.to_s)
                config.paths["db/migrate"].expanded.each do |expand_path|
                    app.config.paths['db/migrate'] << expand_path
                end
            end
        end

    end
end

Now we can simply run rake db:migrate and blog_core will know to include the blog_api migrations.

# ~/blog_core
rake db:migrate

Resources