Multiverse
🔥 Multiple databases for Rails
ActiveRecord supports multiple databases, but Rails < 6 doesn’t provide a way to manage them. Multiverse changes this.
Plus, it’s easy to upgrade to Rails 6 when you get there.
Works with Rails 4.2+
Installation
Add this line to your application’s Gemfile:
gem 'multiverse'Getting Started
In this example, we’ll have a separate database for our e-commerce catalog that we’ll call catalog.
The first step is to generate the necessary files.
rails generate multiverse:db catalogThis creates a CatalogRecord class for models to inherit from and adds configuration to config/database.yml. It also creates a db/catalog directory for migrations and schema.rb to live.
rails and rake commands run for the original database by default. To run commands for the new database, use the DB environment variable. For instance:
Create the database
DB=catalog rails db:createCreate a migration
DB=catalog rails generate migration add_name_to_productsRun migrations
DB=catalog rails db:migrateRollback
DB=catalog rails db:rollbackModels
Also works for models
DB=catalog rails generate model ProductThis generates
class Product < CatalogRecord
endWeb Servers
Only necessary in Rails < 5.2
For web servers that fork, be sure to reconnect after forking (just like you do with ActiveRecord::Base)
Puma
In config/puma.rb, add inside the on_worker_boot block
CatalogRecord.establish_connection :"catalog_#{Rails.env}"Unicorn
In config/unicorn.rb, add inside the before_fork block
CatalogRecord.connection.disconnect!And inside the after_fork block
CatalogRecord.establish_connection :"catalog_#{Rails.env}"Testing
Fixtures
Rails fixtures work automatically.
Note: Referential integrity is not disabled on additional databases when fixtures are loaded, so you may run into issues if you use foreign keys. Also, you may run into errors with fixtures if the additional databases aren’t the same type as the primary.
RSpec
After running migrations for additional databases, run:
DB=catalog rails db:test:prepareDatabase Cleaner
Database Cleaner supports multiple connections out of the box.
cleaner = DatabaseCleaner[:active_record, {model: CatalogRecord}]
cleaner.strategy = :transaction
cleaner.cleaning do
# code
endLimitations
There are a few features that aren’t supported on additional databases.
- Pending migration check
schema_cache.yml
Also note that ActiveRecord::Migration.maintain_test_schema! doesn’t affect additional databases.
Upgrading to Rails 6
Rails 6 provides a way to manage multiple databases 🎉
To upgrade from Multiverse, nest your database configuration in config/database.yml:
# this should be similar to default, but with migrations_paths
catalog_default: &catalog_default
adapter: ...
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
migrations_paths: db/catalog_migrate
development:
primary:
<<: *default
database: ...
catalog:
<<: *catalog_default
database: ...
test:
primary:
<<: *default
database: ...
catalog:
<<: *catalog_default
database: ...
production:
primary:
<<: *default
database: ...
catalog:
<<: *catalog_default
database: ...Then change establish_connection in app/models/catalog_record.rb to:
class CatalogRecord < ActiveRecord::Base
establish_connection :catalog
endAnd move:
-
db/catalog/migratetodb/catalog_migrate -
db/catalog/schema.rbtodb/catalog_schema.rb(ordb/catalog/structure.sqltodb/catalog_structure.sql).
Then remove multiverse from your Gemfile. 🎉
Now you can use the updated commands:
rails db:migrate # run all
rails db:migrate:catalog # runs catalog onlyGenerate migrations with:
rails generate migration add_name_to_products --database=catalogAnd models with:
rails generate model Product --database=catalog --parent=CatalogRecordHappy scaling!
History
View the changelog
Contributing
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development and testing:
git clone https://github.com/ankane/multiverse.git
cd multiverse
bundle install
bundle exec rake test