+
+
+
Introduction Post: www.citusdata.com/blog/2017/01/05/easily-scale-out-multi-tenant-apps/
+
+
ActiveRecord/Rails integration for multi-tenant databases, in particular the open-source Citus extension for PostgreSQL.
+
+
Enables easy scale-out by adding the tenant context to your queries, enabling the database (e.g. Citus) to efficiently route queries to the right database node.
+
+
Installation
+
+
Add the following to your Gemfile:
+
+
gem 'activerecord-multi-tenant'
+
+
+
Supported Rails versions
+
+
All Ruby on Rails versions starting with 6.0 or newer (up to 7.0) are supported.
+
+
This gem only supports ActiveRecord (the Rails default ORM), and not alternative ORMs like Sequel.
+
+
Usage
+
+
It is required that you add multi_tenant
definitions to your model in order to have full support for Citus, in particular when updating records.
+
+
In the example of an analytics application, sharding on customer_id
, annotate your models like this:
+
+
class PageView < ActiveRecord::Base
+ multi_tenant :customer
+ belongs_to :site
+
+ end
+
+class Site < ActiveRecord::Base
+ multi_tenant :customer
+ has_many :page_views
+
+ end
+
+
+
and then wrap all code that runs queries/modifications in blocks like this:
+
+
customer = Customer.find(session[:current_customer_id])
+MultiTenant.with(customer) do
+ site = Site.find(params[:site_id])
+ site.update! last_accessed_at: Time.now
+ site.page_views.count
+end
+
+
+
Inside controllers you can use a before_action together with set_current_tenant, to set the tenant for the current request:
+
+
class ApplicationController < ActionController::Base
+ set_current_tenant_through_filter before_action :set_customer_as_tenant
+
+ def set_customer_as_tenant
+ customer = Customer.find(session[:current_customer_id])
+ set_current_tenant(customer)
+ end
+end
+
+
+
Rolling out activerecord-multi-tenant for your application (write-only mode)
+
+
The library relies on tenant_id to be present and NOT NULL for all rows. However, its often useful to have the library set the tenant_id for new records, and then backfilling tenant_id for existing records as a background task.
+
+
To support this, there is a write-only mode, in which tenant_id is not included in queries, but only set for new records. Include the following in an initializer to enable it:
+
+
MultiTenant.enable_write_only_mode
+
+
+
Once you are ready to enforce tenancy, make your tenant_id column NOT NULL and simply remove that line.
+
+
Frequently Asked Questions
+
+
+
We recommend not using activerecord-multi-tenant on these tables. In case only some records in a table are not associated to a tenant (i.e. your templates are in the same table as actual objects), we recommend setting the tenant_id to 0, and then using MultiTenant.with(0) to access these objects.
+
+
+
The tenant model does not have to be defined. Use the gem as if the model was present. MultiTenant.with
accepts either a tenant id or model instance.
+
+
Credits
+
+
This gem was initially based on acts_as_tenant, and still shares some code. We thank the authors for their efforts.
+
+
License
+
+
Copyright © 2018, Citus Data Inc.
Licensed under the MIT license, see LICENSE file for details.
+