我如何强制RAILS_ENV在耙子任务?

我有这个小耙子任务:

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。 我如何使这个任务按预期工作

对于这个特定的任务,你只需要改变数据库连接,所以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 

另一种select是检查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解决scheme是重新定义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应用程序的引导过程中,RAILS_ENV被初始化如下

 RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV) 

其余的Rails代码直接使用RAILS_ENV

然而,正如Michael在回答他的评论时指出的那样,在运行中切换RAILS_ENV可能是有风险的。 另一种方法是切换数据库连接,这个解决scheme实际上是由默认的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 

它总是增加test如果env是development 。 我解决了想要做一个自定义的db:rebuild任务的情况下同时developmenttest通过运行development第一,然后test第二。 另外,在运行任务之前,我调用我的set_env方法,确保设置ActiveRecord::Tasks::DatabaseTasks.env ,没有这个,数据库连接似乎没有像预期的那样离散处理。 我尝试了所有其他types的断开连接等,但这没有进一步的代码工作。

 def set_env(env) Rails.env = env.to_s ENV['RAILS_ENV'] = env.to_s ActiveRecord::Tasks::DatabaseTasks.env = env.to_s end 

这里是我的完整的db.rake文件的同时多环境db:rebuilddb:truncate的要点