この小さなすくいのタスクがあります:
namespace :db do
namespace :test do
task :reset do
ENV['Rails_ENV'] = "test"
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
Rake::Task['db:migrate'].invoke
end
end
end
さて、実行すると、ハードコードしようとしたRails_ENVは無視されます。このタスクを期待どおりに機能させるにはどうすればよいですか
この特定のタスクでは、DB接続を変更するだけでよいため、Adamが指摘したように、これを行うことができます。
namespace :db do
namespace :test do
task :reset do
ActiveRecord::Base.establish_connection('test')
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
Rake::Task['db:migrate'].invoke
ActiveRecord::Base.establish_connection(ENV['Rails_ENV']) #Make sure you don't have side-effects!
end
end
end
タスクがより複雑で、ENVの他の側面が必要な場合は、新しいrakeプロセスを最も安全に生成できます。
namespace :db do
namespace :test do
task :reset do
system("rake db:drop Rails_ENV=test")
system("rake db:create Rails_ENV=test")
system("rake db:migrate Rails_ENV=test")
end
end
end
または
namespace :db do
namespace :test do
task :reset do
if (ENV['Rails_ENV'] == "test")
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
Rake::Task['db:migrate'].invoke
else
system("rake db:test:reset Rails_ENV=test")
end
end
end
end
Rails 3では、使用する必要があります
Rails.env = "test"
Rake::Task["db:drop"].invoke
の代わりに
Rails_ENV = "test"
Rake::Task["db:drop"].invoke
別のオプションは、envを確認して続行を拒否することです。
unless Rails.env.development?
puts "This task can only be run in development environment"
exit
end
または、本当に続行したいかどうかを尋ねます。
unless Rails.env.development?
puts "You are using #{Rails.env} environment, are you sure? y/n"
continue = STDIN.gets.chomp
exit unless continue == 'y'
end
最もクリーンでシンプルなソリューションは、Rails_ENV
(ENV['Rails_ENV']
ではなく)を再定義することです。
namespace :db do
namespace :test do
task :reset do
Rails_ENV = "test"
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
Rake::Task['db:migrate'].invoke
end
end
end
Rails application Rails_ENVは次のように初期化されます。
Rails_ENV = (ENV['Rails_ENV'] || 'development').dup unless defined?(Rails_ENV)
残りのRailsコードはRails_ENV
を直接使用します。
ただし、マイケルが自分の答えへのコメントで指摘したように、Rails_ENV
をその場で切り替えることは危険です。別のアプローチは、データベース接続を切り替えることです。実際、このソリューションはデフォルトのdb:test
タスクで使用されます
ActiveRecord::Base.establish_connection(:test)
もちろん、最良の方法は、rakeタスクを実行するときにコマンドラインから環境を指定することですが、何らかの理由でそれがしたくない場合は、これを行うことができます:
ENV["Rails_ENV"] = 'test'
Rails_ENV.replace('test') if defined?(Rails_ENV)
load "#{Rails_ROOT}/config/environment.rb"
そして、これでうまくいくはずです。
database_tasks.rb
には奇妙なコードがあります:
def each_current_configuration(environment)
environments = [environment]
environments << 'test' if environment == 'development'
configurations = ActiveRecord::Base.configurations.values_at(*environments)
configurations.compact.each do |configuration|
yield configuration unless configuration['database'].blank?
end
end
Envがtest
の場合、常にdevelopment
を追加します。最初にdevelopment
を実行し、次にtest
を実行することにより、development
とtest
を同時に処理するカスタムdb:rebuild
タスクを実行したい場合の問題を解決しました。さらに、タスクを実行する前に、set_env
メソッドを呼び出してActiveRecord::Tasks::DatabaseTasks.env
を設定します。これがないと、データベース接続は期待どおりに環境で個別に処理されないようです。他のすべての種類の切断などを試しましたが、これはそれ以上のコードなしで機能しました。
def set_env(env)
Rails.env = env.to_s
ENV['Rails_ENV'] = env.to_s
ActiveRecord::Tasks::DatabaseTasks.env = env.to_s
end