Ruby on Rails is a popular web framework known for rapid development backed by a great community. This post is intended to introduce and encourage you to build a more modular rails application. I maintain a collection of resources if you’d like to learn more.
Creating the Engine
Most applications require user authentication so I think that would be a great first engine to create. I’m going to walk you through the creation of ConnectBy
.
Note: Credit for the naming conventions here goes to Vlad and the Evil Martians. You can check out his talk at RailsConf 2020.
The Host
I’ll refer to our rails app as the host application.
rails new host_app --database postgresql
We will install Devise in our ConnectBy
engine. Let’s get started.
Generate the plugin
Our engines are installed locally in /engines
and gems in /gems
. Run the rails plugin generator from the host’s root.
(using whitespace for clarity)
./host_app $ rails plugin new engines/connect_by
--mountable
--database postgresql
--skip-git
--skip-keeps
--skip-action-text
--skip-action-cable
--skip-sprockets
--skip-javascript
--skip-turbolinks
--skip-test
--skip-system-test
--skip-gemfile-entry
--dummy_path=spec/dummy
Flags explained
Skip setting up test_unit
and create a dummy app that we will later use with rspec.
--skip-test
--skip-system-test
--dummy_path=spec/dummy
Our host app will dynamically load all of our engines.
--skip-gemfile-entry
Our frontend won’t live in our engine.
--skip-action-cable
--skip-sprockets
--skip-javascript
--skip-turbolinks
Version Management
Add a rails-version file to our host app so each engine can reference it.
./host_app $ echo "6.0.3.2" > .rails-version
Update the gemspec
Load our engine in the host application’s gemfile.
# Gemfile
Dir.glob(File.expand_path("../engines/*", __FILE__)).each do |path|
gem File.basename(path), path: path
end
Install Devise
Review devise’s latest getting start instructions and use their devise inside a mountable engine wiki as an additional resource.
Add devise to our engine’s gemfile.
# engines/connect_by/Gemfile
gem "devise", "~> 4.7.1"
Load devise.
# engines/connect_by/lib/connect_by.rb
require "connect_by/version"
module ConnectBy
end
require "devise"
require "connect_by/engine"
Bundle connect_by
and our host.
./host_app $ bundle install
./host_app/engines/connect_by $ bundle install
Install devise and create our user model.
./host_app/engines/connect_by $ rails generate devise:install
./host_app/engines/connect_by $ rails generate devise user
Update our devise configuration.
# engines/connect_by/initializers/devise.rb
config.parent_controller = 'ConnectBy::ApplicationController'
config.router_name = :connect_by
Install our new migrations on the host application.
./host_app $ rails connect_by:install:migrations
Migrate your host app’s database.
./host_app $ rails db:create db:migrate
Mount our engine’s route in the host.
# config/routes.rb
Rails.application.routes.draw do
mount ConnectBy::Engine, at: "/a"
end
We are creating an isolate namespaced engine so we need to tell devise that we are using their controllers in their module
.
# engines/connect_by/config/routes.rb
devise_for :users,
class_name: "ConnectBy::User",
module: :devise
Frontend
I’ll drop the frontend from ConnectBy
to avoid taking away from the tutorial. Isolated frontends with Webpacker 4 can get very involved (How to use webpacker from within engines?).
Remove assets and view layouts from the engine.
./host_app/engines/connect_by $ rm -rf ./app/assets
./host_app/engines/connect_by $ rm -rf ./app/views/layouts
Start up the server and navigate to /a/users/sign_in
to confirm it worked.
Takeaway
We took a modular approach and created a rails engine for our user account’s.
The source code for this part is on github.
Next Steps
Part 2 focuses on setting up the test suite, specifically rspec.
- Part 1 - Create Your First Rails Engine
- Part 2 - Test Your First Rails Engine
- Part 3 - Configure Your First Rails Engine
Useful Resources
I have compiled a list of useful resources for rails engines and the modular monolith architecture.
Scale With Rails Engines
Need help scaling your rails application with a modular monolith? Talk to us