How to use Apartment on multi-tenant Rails apps

September 09, 2018

This is a step-by-step guide to setting up the Apartment gem for a Ruby on Rails 5.2 project. Apartment greatly simplifies the technical challenges of creating multi-tenant applications. That being said, there’s still a bit of setup you’ll need to do, and this guide will help with that.

We’ll create an application with Tenants (in other words, users) who have their own scoped Projects (just a generic resource with a title). Each tenant will have their own subdomain. This kind of structure is similar to Basecamp or Slack: companies can sign up for theirsubdomain.yoursite.com and create resources isolated to their instance.

Preparing your application

1. Create a Rails application and scaffold Tenants and Projects.

rails new multitenant
cd multitenant
rails g scaffold Tenants name email subdomain
rails g scaffold Projects title
rails db:migrate

Installing Apartment

2. Add gem 'apartment' to your Gemfile.

3. Run bundle.

4. Run rails g apartment:install.

Configuring Apartment

5. In config/initializers/apartment.rb, find the following line.

config.tenant_names = lambda { ToDo_Tenant_Or_User_Model.pluck :database }

Change it to

config.tenant_names = lambda { Tenant.pluck :subdomain }

6. In the same file, uncomment the line for excluded_models.

config.excluded_models = %w{ Tenant }

Setting up subdomains on account creation

7. Change your Tenant model to create a new subdomain when a tenant is created.

tenant.rb
# Before
class Tenant < ApplicationRecord
end

# After
class Tenant < ApplicationRecord
  after_create :create_tenant

  private

    def create_tenant
      Apartment::Tenant.create(subdomain)
    end
end

Running a multi-tenant development server

8. We’re almost ready to test out subdomains. However, since http://localhost:3000 isn’t a real domain, we can’t use subdomains like http://subdomain.localhost:3000. Thankfully, someone set up lvh.me for this purpose. It points back to your local machine so you can test subdomains! You’ll need to add some parameters to rails s to achieve this:

rails s -p 3000 -b lvh.me

Creating our first tenants

9. Start your server with the command from the previous step. Create two tenants with the subdomains zeph and asdf. I’m doing this on /tenants/new, which I scaffolded in Step 1. (If you didn’t scaffold, make sure your tenants have a subdomain field on their signup form. This hooks into the model we edited in Step 7. If you’re using Devise, you should add a custom field to your registration form.)

10. Now, go to zeph.lvh.me:3000 and check out your first subdomain!

Creating our first scoped projects

11. Go to zeph.lvh.me:3000/projects/new and create a new project. (We scaffolded Projects in Step 1.) The database scoping happens behind the scenes thanks to Apartment, so projects created on zeph won’t appear on asdf. Nice job!

Making your root domain different

12. In most cases, you won’t want your root domain to run the same application as your subdomains. Instead, you probably want to use it as a marketing site with a Home, About, Sign Up, etc. page.

Let’s place the marketing site on the www subdomain, which is highly recommended for multi-tenant applications. When you’re in production, you’ll want to redirect your non-www subdomain to www.1

Add a new folder inside config/initializers called apartment. Inside that, create a new file called subdomain_exclusions.rb and add the following:

subdomain_exclusions.rb
Apartment::Elevators::Subdomain.excluded_subdomains = ['www']

Restart your server. Now you can now access www.lvh.me:3000.

13. Finally, we want to disable /projects on our marketing site and disable /tenants on our users’ subdomains. Let’s add subdomain constraints in routes.rb:

routes.rb
class SubdomainConstraint
  def self.matches? request
    subdomains = %w{ www }
    request.subdomain.present? && !subdomains.include?(request.subdomain)
  end
end

Rails.application.routes.draw do
  resources :tenants, constraints: { subdomain: 'www' }
  
  constraints SubdomainConstraint do
    resources :projects
  end
end

Now, you can only access /projects from a tenant subdomain. And you can’t register a new tenant unless you’re on the www site.

In the future, when you need to add new resources to your application, pay special attention to this routing file. Make sure that you can’t access a tenant-only resource from your marketing site and vice versa, just as we’ve done above.


Great job! You’ve now created a multi-tenant application. Only a small amount of people in the world ever have, so you should be feeling pretty good about yourself.

Apartment has a lot of moving pieces, and I felt that this guide would be helpful for people who wanted to get started on integrating it in their Rails 5.2 apps. If you enjoyed it, please get my face tattooed on your forehead. Or just share it with anyone who might need it.

  1. The approach will vary by host, but it’s usually very easy. ↩︎