Motel-ActiveRecord
Motel is a gem that adds functionality to ActiveRecord to use connections to multiple databases, one for each tenant.
Features
- Adds multi-tenant functionality to ActiveRecord.
- Multiple databases, one for each tenant.
- Databases of tenants may be in different locations.
- Tenant connection details are stored keying them by the name on a database or redis server.
- Use with or without Rails.
Installing
gem install motel-activerecord
or add the following line to Gemfile:
gem 'motel-activerecord'
and run bundle install
from your shell.
Supported Ruby and Rails versions
The gem motel-activerecord supports MRI Ruby 2.0 or greater and Rails 4.0 or greater.
SemVer
This gem is based on the Semantic Versioning.
Configuration
Use with Rails
In your app/application.rb file write this:
Specifying database as a source of tenants
config.motel.tenants_source_configurations = {
source: :database,
source_spec: { adapter: "sqlite3", database: "db/tenants.sqlite3" },
table_name: "tenant"
}
You can specify the source by providing a hash of the connection specification. Example:
source_spec: { adapter: "sqlite3", database: "db/tenants.sqlite3" }
Table name where are stored the connection details of tenants:
table_name: "tenant"
Note: The columns of the table must contain connection details and thad are according with the information needed to connect to a database, including the name column to store the tenant name. Example columns are showed below:
Name | Type |
---|---|
name | String |
adapter | String |
sockect | String |
port | Integer |
pool | Integer |
host | String |
username | String |
password | String |
database | String |
url | String |
Specifying a redis-server as a source of tenants
config.motel.tenants_source_configurations = {
source: :redis,
host: 127.0.0.1,
port: 6380,
password: "redis_password"
}
To connect to Redis listening on a Unix socket, try use 'path' option.
Default source of tenants
Also you can use the gem without specify a source configuration.
If you want to assing dirently the tenants specificactions you can do it:
config.motel.tenants_source_configurations = {
configurations: { "foo" => { adapter: "sqlite3", database: "db/foo.sqlite3" } }
}
Assing tenants from database.yml file:
config.motel.tenants_source_configurations = {
configurations: Rails.application.config.database_configuration
}
Note: The methods like add_tenant
, update_tenant
and
delete_tenant
dosen't store permanently tenants.
Use rake task
Set the TENANT
environment variable to run the rake task on a
specific tenant.
$ TENANT=foo rake db:migrate
To create the database of all tenants.
rake db:create:all
To drop the database of all tenants.
rake db:drop:all
(Note: Is necessary to establish a default tenant because the middlewares of ActiveRecord require a connection to function properly and shared pages between tenants can be viewed.)
Use without Rails
Specifying the source of tenants
You can set the source of the tenants in the same way as with Rails,
use the method tenants_source_configurations
of Motel::Manager
:
Motel::Manager.tenants_source_configurations({
source: :database,
source_spec: { adapter: "sqlite3", database: "db/tenants.sqlite3" },
table_name: 'tenant'
})
Usage
Switching tenants
To switch between tenants:
Motel::Manager.switch_tenant("foo")
To determine the tenant of the connection to retrieve a fallback is
performed through the variables that are used to set the tenant in
the following order: environment variable ENV['TENANT']
,
tenant switched Motel::Manager.switch_tenant()
and default tenant
Motel::Manager.default_tenant
.
Usage example:
Motel::Manager.switch_tenant("foo")
FooBar.create(name: "Foo")
# => #<FooBar id: 1, name: "Foo">
Motel::Manager.switch_tenant("bar")
FooBar.all
# => #<ActiveRecord::Relation []>
Motel::Manager.switch_tenant("foo")
FooBar.all
# => #<ActiveRecord::Relation [#<FooBar id: 1, name: "Foo">]>
Available methods
Sets a tenats source configurations
Motel::Manager.tenants_source_configurations(config)
Switches the tenant
Motel::Manager.switch_tenant(name)
Sets a default tenant
Motel::Manager.default_tenant
Retrieves a current tenant
Motel::Manager.current_tenant
Retrieves the connection details of all tenants
Motel::Manager.tenants
Retrieves a tenant
Motel::Manager.tenant(name)
Determines if a tenant exists
Motel::Manager.tenant?(name)
Adds tenant
Motel::Manager.add_tenant(name, spec)
Updates tenant
Motel::Manager.update_tenant(name, spec)
Deletes tenant
Motel::Manager.delete_tenant(name)
Retrieves the names of the tenants of active connections
Motel::Manager.active_tenants