😊

Rakeタスクの実行に前処理を追加する(Multi DB対応)

に公開

やりたいこと

Rakeタスクの実行に前処理を追加する をMulti DBにも対応させる。
Multi DB環境では、 db:drop:primary db:drop:secondary のようにデータベースを指定して実行することができるので、これらの実行時前に変数のチェックを行う。

前提:Multi DBの設定

primary secondary の2つのDBを仮定する。

database.yml
default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  primary:
    <<: *default
    database: storage/development_primary.sqlite3
  secondary:
    <<: *default
    database: storage/development_secondary.sqlite3

解1:愚直に列挙する

正直、データベースが増える頻度を考えるとこれで十分ではある。

Rakefile
namespace :db do
  task :abort_if_no_run do
    abort 'Please set RUN environment variable.' if Rails.env.production? && ENV['RUN'] != 'true'
  end

  Rake::Task['db:drop'].enhance(['abort_if_no_run'])
  Rake::Task['db:drop:primary'].enhance(['abort_if_no_run'])
  Rake::Task['db:drop:secondary'].enhance(['abort_if_no_run'])
end

ループにしてもいいが、可読性や記述量の観点で本質としてはそこまで差がない。

Rakefile
namespace :db do
  task :abort_if_no_run do
    abort 'Please set RUN environment variable.' if Rails.env.production? && ENV['RUN'] != 'true'
  end

  Rake::Task['db:drop'].enhance(['abort_if_no_run'])
  %w[primary secondary].each do |database|
    Rake::Task["db:drop:#{database}"].enhance(['abort_if_no_run'])
  end
end

解2:configを読んでループで指定する

ActiveRecord::Base.configurations.configs_for(env_name: Rails.env) でdbのリストが取れるので、それをループして処理する。
ただ、そのまま実行しても空の配列が返ってくるので、 db:load_config のタスクを実行しておく。

Rakefile
namespace :db do
  task :abort_if_no_run do
    abort 'Please set RUN environment variable.' if Rails.env.production? && ENV['RUN'] != 'true'
  end

  Rake::Task['db:load_config'].invoke
  ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
    Rake::Task["db:drop:#{db_config.name}"].enhance(['abort_if_no_run'])
  end

  Rake::Task['db:drop'].enhance(['abort_if_no_run'])
end

実行結果

./bin/rails db:drop:primary RAILS_ENV=production
Please set RUN environment variable.

Discussion