Active Record で複数のデータベース利用 - Railsガイドにある通り、複数DBを使うときは database.yml
をこんな風に3層にしますよね。
default_primary: &default_primary
adapter: mysql2
encoding: utf8mb4
collation: utf8mb4_bin
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV['PRIMARY_DATABASE_USER'] || 'root' %>
password: <%= ENV['PRIMARY_DATABASE_PASSWORD'] %>
host: <%= ENV['PRIMARY_DATABASE_HOST'] || 'localhost' %>
default_animal: &default_animal
<<: *default_primary
host: <%= ENV['ANIMAL_DATABASE_HOST'] || 'localhost' %>
username: <%= ENV['ANIMAL_DATABASE_USER'] || 'root' %>
password: <%= ENV['ANIMAL_DATABASE_PASSWORD'] %>
development:
primary:
<<: *default_primary
database: <%= ENV['PRIMARY_DATABASE_NAME'] || 'project_development' %>
animal:
<<: *default_animal
database: <%= ENV['ANIMAL_DATABASE_NAME'] || 'project_animal_development' %>
...
例えば、development環境の primary
に、 db/Schemafile
をapplyしたいとします。
ここで単純に以下のようにするとエラーになります。
$ bundle exec ridgepole -c config/database.yml -E development -f db/Schemafile --apply
[ERROR] database configuration does not specify adapter
/usr/local/bundle/gems/activerecord-6.1.7.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:1198:in `resolve_pool_config'
この結果はある意味当然で、 primary
と animal
のどちらにapplyすればいいか指定していないため、ridgepoleが database.yml
の development
キー直下を直接読みに行って、adapterが見つからずエラーになっているわけですね。
どうすればDBを指定できるのかしばらく調べていたのですが、ridgepoleのbinコマンドのソースコードを眺めていたら、 spec_name
というそれっぽい変数がありました。
# https://github.com/ridgepole/ridgepole/blob/1.2/bin/ridgepole
ARGV.options do |opt|
# ...
opt.on('-s', '--spec-name SPEC_NAME') { |v| spec_name = v }
# ...
client = Ridgepole::Client.new(Ridgepole::Config.load(config, env, spec_name), options) if config
これじゃない?
# https://github.com/ridgepole/ridgepole/blob/1.2/lib/ridgepole/cli/config.rb
module Ridgepole
class Config
class << self
def load(config, env = 'development', spec_name = '')
# ...
if parsed_config.key?(spec_name.to_s)
parsed_config.fetch(spec_name.to_s)
else
parsed_config
end
end
# ...
これじゃん。
ということで、 spec_name
を指定すればいいようです。
-s
オプションの指定でOKです。
$ bundle exec ridgepole -c config/database.yml -E development -s primary -f db/Schemafile --apply
このPRで入ったオプションのようですね。
今になって思うと、リポジトリ内を「multiple database」で検索すれば情報が見つかる話でした。
この -s
オプションですが、 ridgepole --help
を見ても説明は薄めです。
-s, --spec-name SPEC_NAME
説明がほとんどないということは、複数DBを使うときに spec_name
を指定することが自明であり、 spec
という単語にymlのキーやデータベース名という意味がある(そして自分がそれを理解していなかった)、という話なのかと思ったのですが、調べてみてもそういう意味にはたどり着けませんでした。
ということで、自分のようにオプションが分からない人に向けてこの記事を書いています。
命名経緯についてもう少し調べようと、 -s
オプションが追加されたPRを眺めてみると、当時はRails内部で spec_name
という変数を使ってデータベース名を管理していたことが分かりました。
おそらくこの名前を引っ張ってきたのでしょう。
# https://github.com/rails/rails/blob/1c24f01596d8d50bf10cb9d205b5d2c08ea9d6c6/activerecord/lib/active_record/database_configurations.rb#L33-L35
# * <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
# to +nil+. If no +env_name+ is specified the config for the default env and the
# passed +spec_name+ will be returned.
ちなみに、Railsの方の変数名は、2023年2月現在では単なる name
になっています。
# https://github.com/rails/rails/blob/0614aa6e0aeb11cc19e1ede13da8b602191c00ea/activerecord/lib/active_record/database_configurations.rb#L34-L36
# * <tt>name:</tt> The db config name (i.e. primary, animals, etc.). Defaults
# to +nil+. If no +env_name+ is specified the config for the default env and the
# passed +name+ will be returned.
歴史を感じる一幕でした。