Every customer is having their own software instance, own DB and it serves for only one customer. Here, the software can be customized to meet the specific customer requirements as it is independent.
Multi tenancy:In this case, single instance of software application serves multiple customers. Here, we call each customer as a tenant. Here we can modify the UI rules and business rules but cannot modify application code since the same architecture is shared by multiple customers. It is economical since the software development and maintenance costs are shared between customers. But updates can be done by provider only.
Advantages: 1. Single hardware that manages multiple customers. 2. Cost savings. Cost can be shared between all the customers. 3. Easy maintenance 4. Configuration can be changed without touching codebase. 5. New tenants can be added easily since it is a shared architecture. Disadvantages: DB customization will be difficult to handle since it is a single DB shared between multiple customers with different tenants. There are milia, acts_as_tenant and apartment gem to handle multi-tenancy in the Rails application. Apartment Gem:This gem adopts a different way to deal with multi tenancy. It works by making another DB for each tenant. For PostgreSql, it creates another Schema for each tenant. I like this approach in light of the fact that, for this situation, the information is really disengaged. The database is not shared and on the off chance that you need to erase a client’s information, all you need to do is to simply drop their database (or pattern). It also supports Elevators and allows for the automatic switch between the customer’s tenant and thereby automating the switching logic.
This gem helps us to deal with multi tenancy in Rails application. Add the line below, to your Gemfile and perform bundle install.gem 'apartment'
To generate apartment initializer file, run the command below:
bundle exec rails generate apartment:install
config.excluded_models = %w{ Tenant }
Here, we can specify the tenants which are of global scope, such as the Authentication model which is a common one for all the tenants.
Here, I will be creating a Customer with subdomains, so, whenever customer logs in to the application, apartment fetches the subdomains and will query the database, based on tenant subdomain.
rails g scaffold Customer name:string tenant_domain:string
do
rails db:migrate
We need to create apartment tenant, once we have created the customer.
Apartment::Tenant.create('tenant_name') - To create tenant
Use after_create callback in your model to create tenants.
def create_tenant
Apartment::Tenant.create(tenant_domain)
end
Once the above callback gets executed, all the migrations will run under that respective tenant.
Switching of subdomains will be handled automatically when we request the application with subdomains. Below is the configuration line to switch the tenants based on subdomain.
Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'
To switch between the tenants
Apartment::Tenant.switch!('tenant_name')
All your ActiveRecord queries will be routed to the specific tenant when switch is called for.
Switch will be in the root scope when you call with no arguments.
Even tenant switch can be done based on the first subdomain but we need to set config in the initializer file. We can even exclude some subdomains here, such as the normal subdomain.
config.middleware.use 'Apartment::Elevators::FirstSubdomain'
Apartment::Elevators::FirstSubdomain.excluded_subdomains = ['www']
We can also restrict the users not to create some domains such as www, admin. These domains will not be available for the users while they were being registered.
Need to uncomment below config line in the apartment initializer file.
Apartment::Elevators::Subdomain.excluded_subdomains = ["public", "www", and "admin" ]
We can also switch, based on the full host. Here, we need to find the corresponding tenant name in the hash by using the following config line. We need to add the line below to your application.rb
config.middleware.use 'Apartment::Elevators::HostHash', {'example.com' => 'example_tenant'}
Drop tenants:
The command below can be used to drop tenants:
Apartment::Tenant.drop('tenant_name')
Please check gem official resource to find more documentation.