2009-07-07 75 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