Multitenant Rails Application using acts_as_tenant and Devise

There are many use cases for achieving multitenancy in a Rails application. Two of the best gems to use for this purpose are apartment and acts_as_tenant. Both work well and are commonly used. Here are some tips for using acts_as_tenant along with Devise, the most common user authentication gem, to create a multitenant Rails application

Setting up Devise

Add devise gem to your Gemfile and run bundle install.

1
gem "devise"

Run the following commands in your terminal:

1
2
rails generate devise:install
rails generate devise User

Scaffolding

Create a scaffold for which we want to achieve multitenancy.

1
rails generate scaffold Project name

Creating models and necessary migrations

Run the following migrations in your terminal:

1
2
rails generate model Account user:references
rails generate migration add_account_to_projects

Add this in your add_account_to_projects migration:

1
2
3
4
5
6
class AddAccountToProjects < ActiveRecord::Migration[6.0]
  def change
    add_column :projects, :account_id, :integer
    add_index :projects, :account_id
  end
end

Run rails db:migrate.

Setting up acts_as_tenant

Now add acts_as_tenant gem in your Gemfile and run bundle install.

1
gem "acts_as_tenant"

Add this line to your project.rb:

1
2
3
class Project < ApplicationRecord
  acts_as_tenant :account
end

And the following lines to user.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :account

  before_validation :set_account

  def set_account
    self.build_account
  end
end

And this to account.rb:

1
2
3
class Account < ApplicationRecord
  belongs_to :user
end

Setting current tenant in the application controller

Now in the application_controller.rb file, put this code:

1
2
3
4
5
6
7
8
9
10
11
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  set_current_tenant_through_filter
  before_action :set_current_account

  def set_current_account
    return unless current_user.present?
    current_account = current_user.account
    ActsAsTenant.current_tenant = current_account
  end
end

That’s it. You have configured acts_as_tenant in your Rails application and it will set tenant to the current user’s account for every query to Project model to refer to.