前提
Railsガイドで解説されている、レプリカとかリードオンリーとかは考えず、単に2つのデータベースをモデルに応じて使い分けることを目的とします*1。
手順
1. config/database.yml を編集する
まず config/database/yml
を編集します。データベースが1つの場合には、production:
や development:
の下の階層にデータベースの接続設定を書きますが、複数のデータベースを用いる場合は、それらのデータベースの接続設定に名前を付けてあげて、その名前のひとつ下の階層にデータベースの接続設定を書きます。
また、それぞれの接続設定に対して migrations_paths
を書く必要があります。データベースごとに、適用されるマイグレーションの場所を分けます。
YAMLはたとえば、以下のように書きます。
default: &default adapter: postgresql encoding: unicode pool: <%= ENV.fetch('RAILS_MAX_THREADS') { 5 } %> host: <%= ENV.fetch('PG_HOST', 'localhost') %> port: <%= ENV.fetch('PG_PORT', '5432') %> username: <%= ENV.fetch('PG_USER', 'ANATA_NO_NAMAE') %> password: <%= ENV.fetch('PG_PASSWORD', 'ANATA_NO_PASSWORD') %> production: tomato: <<: *default database: tomato_no_database_production melon: <<: *default database: melon_no_database_production migrations_paths: db/melon_no_migrate development: tomato: <<: *default database: tomato_no_database_development melon: <<: *default database: melon_no_database_development migrations_paths: db/melon_no_migrate test: tomato: <<: *default database: tomato_no_database_test melon: <<: *default database: melon_no_database_test migrations_paths: db/melon_no_migrate
上記の書き方により、tomato
と melon
の2つのデータベースの接続設定が作られました。
2. app/models 配下に、第2のデータベースを司るモデルファイルを作る
データベースが1つの場合には app/models/application_record.rb
が、モデルのファイルのすべてを司るファイル(全てのモデルファイルが継承をするファイル)でした。データベースが2つの場合は、2つ目のデータベースを司るためのファイルを作ります。ここがポイントかと思います。
2-1. ファイル名をどうするか
まずファイル名をどうするかですが、app/models
配下には大量のモデルファイルが作られるため、それらと区別できるようなファイル名にする必要があります*2。Railsガイドでは HogehogeBase
というように Base
を接尾語として付与しています。
個人的には、application_record.rb
という既存のファイルにならって、application_hogehoge_record.rb
のようにするほうが、ファイル一覧の並びでの視認性という意味でもわかりやすいかなと思っています。
2-2. 抽象クラスとなるモデルのファイルを作る
ファイル名が決まったら、内容を以下のように書きます。ファイル名を application_hogehoge_record.rb
としたと仮定します。
class ApplicationHogehogeRecord < ApplicationRecord self.abstract_class = true connects_to database: { writing: :melon, reading: :melon } end
ApplicationHogehogeRecord
は ApplicationRecord
を継承することに注意してください*3。
そして、connects_to
メソッドで、このモデルが接続するデータベースを決めます*4。
database: { writing: :melon, reading: :melon }
という引数を与えることで、ApplicationHogehogeRecord モデルは、config/database.yml
で命名した、melon
というデータベースに接続することになります。
writing
と reading
は、CRUD の内容ごとに接続するデータベースをさらに区別する場合の指定ですが、今回は冒頭の「前提」の下での話になるので同じ値である :melon
を指定しています。レプリケーションとかラウンドロビンとかを考える場合には細かく設定するのがいいでしょう。
2-3. 作った抽象クラスを継承したモデルファイルを作る
第2のデータベースを用いるモデルファイルは、application_record.rb
ではなく、前述の application_hogehoge_record.rb
を継承します。
たとえば、foobar.rb
というモデルファイルが第2のデータベースを用いる場合には、app/models/foobar.rb
の内容は次のようになります。
class Foobar < ApplicationHogehogeRecord end
さて、rails g model
でモデルファイルを作る場合には、--database
オプションを用いて例えば --database melon
のように指定することで、作成されるマイグレーションファイルが config/database.yml
で指定したディレクトリのはいかに作成されます。
ただし、留意しておくこととしては、application_hogehoge_record. rb
を継承したファイルを rails g model
で作る場合には制限があるということです。継承するモデルを application_record.rb
以外にする場合は --parent
オプションを用いるのですが、このオプションを用いるとマイグレーションファイルが生成されません。
所定のディレクトリ配下*5に手動でマイグレーションファイルを作る必要があります*6。これは、--parent
オプションを使用する場合は STI の実装を前提としているからです。以下の Stack Overflow のとおりです。
--parent
オプションを使わないで rails g model
を実行すると、生成されたクラスは ApplicationRecord
を継承しているので、その部分を手動で ApplicationHogehogeRecord
に書き換える必要があります。
どちらの方法を採るにしてもひと手間入りますので注意が必要です。これをいい感じにしてくれるコードを書いてもいいと思いますが*7、まあ大した手間ではないので手動で良いかなと思います。
3. あとは普段どおりにモデルを扱う
上記の設定ができたならば、あとは特に意識すること無くモデルを扱えます。モデルに応じて用いられるデータベースが自動で選択されます。
一度設定すれば、あとは意識せずに操作できるでしょう*8。
4. db:migrate
rails db:migrate
を行うと、config/database.yml
に書かれている所定のディレクトリにあるマイグレーションファイルを判断して、自動でデータベースを割り振ってマイグレーションを行ってくれます。スキーマファイルもデータベースごとに作られます*9。
特定のデータベースだけにマイグレーションしたい場合には、$ rails db:migrate:melon
のようにして末尾に :HOGEHOGE
とデータベース接続設定名*10を指定します。
補足
- 異なるデータベース同士でもアソシエーションを(無意識に)用いることができます
- データベースレベルで制約をつけるのは別の話になります
- 3つ以上のデータベースを用いる場合には上記の方法を応用すればいいでしょう
*1:ActiveRecord::Middleware::DatabaseSelector
*2:区別できなくても問題ないといえばないのですが……
*3:ここがポイントかと思います
*4:「このモデルが接続する」とありますがこのモデルは抽象クラスなので、このクラスを継承したクラスが接続するデータベースを実質的に決めることになります
*5:config/database.yml 内で migrations_paths: によって指定した場所
*6:rails g migration する際には --database オプションが必要です
*7:すでにあるかも
*8:ただしデータベースをまたいだリレーションについては厳しいものがありますが……
*9:melon_schema.rb のように、第2のデータベースのスキーマファイルには接頭語が付与されます
*10:config/database.yml に書かれている