2009-07-07 71 views
43

我这个小耙子任务:如何在rake任务中强制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。我如何使这个任务按预期工作

回答

48

对于这个特殊的任务,你只需要改变数据库连接,从而亚当指出的那样,你可以这样做:

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的其他方面,你是最安全产生一个新的耙过程:

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 
4

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

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

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

而且应该这样做。

+0

您可能只能够`需要environment'`的“配置/重装代替它。 – ealdent 2009-07-07 03:13:22

+0

什么黑客,像冠军一样工作。 – 2009-07-07 03:15:32

+0

它似乎是没有要求或负载耙任务... – 2009-07-07 03:17:35

6

最干净和简单的解决方案将是重新定义如下

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

的Rails代码的其余部分直接使用RAILS_ENVRAILS_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的引导过程被初始化。

但是,正如Michael在回答他的回答时指出的那样,动态切换RAILS_ENV可能有风险。另一种方法是将切换数据库连接,这一解决方案实际上是在使用默认db:test任务

ActiveRecord::Base.establish_connection(:test) 
17

在Rails 3,你将不得不使用

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

,而不是

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

另一种选择是检查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 
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 

它总是添加test如果ENV是development。我解决了想通过运行development第一个和test秒来同时执行developmenttest定制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 

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