如何在rake任务中强制执行RAILS_ENV?

时间:2009-07-07 03:02:51

标签: ruby-on-rails ruby rake

我有这个小小的佣金任务:

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

6 个答案:

答案 0 :(得分:49)

对于此特定任务,您只需要更改数据库连接,正如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

答案 1 :(得分:19)

在Rails 3中,你必须使用

Rails.env = "test"
Rake::Task["db:drop"].invoke

而不是

RAILS_ENV = "test"
Rake::Task["db:drop"].invoke 

答案 2 :(得分:10)

另一种选择是检查环境并拒绝继续:

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

答案 3 :(得分:6)

最干净,最简单的解决方案是重新定义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

然而,正如迈克尔在对他的回答的评论中指出的那样,即时切换RAILS_ENV可能会有风险。另一种方法是切换数据库连接,这个解决方案实际上是由默认的db:test任务

使用的
ActiveRecord::Base.establish_connection(:test)

答案 4 :(得分:4)

当然,最好的方法是在运行rake任务时从命令行指定环境,但如果由于某种原因这不是你想要做的,你可以这样做:

ENV["RAILS_ENV"] = 'test'
RAILS_ENV.replace('test') if defined?(RAILS_ENV)

load "#{RAILS_ROOT}/config/environment.rb"

这应该可以解决问题。

答案 5 :(得分:3)

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。我通过首先运行db:rebuilddevelopment秒来解决了希望同时为testdevelopment执行自定义test任务的情况。此外,在运行任务之前,我调用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

Here is a gist of my full db.rake file with simultaneous multi-environment db:rebuild and db:truncate