47

我有这个小耙任务:

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

4

6 回答 6

50

对于这个特定任务,您只需要更改数据库连接,正如 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
于 2009-07-07T04:10:06.403 回答
19

在 Rails 3 中,您必须使用

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

代替

RAILS_ENV = "test"
Rake::Task["db:drop"].invoke 
于 2011-08-30T17:09:32.703 回答
11

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

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
于 2013-02-27T17:32:07.103 回答
7

最干净和最简单的解决方案是重新定义RAILS_ENV(not 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)
于 2009-07-07T19:59:08.993 回答
4

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

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

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

这应该可以解决问题。

于 2009-07-07T03:12:26.880 回答
4

有一些奇怪的代码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,如果没有这个,数据库连接似乎不会像预期的那样针对环境进行离散处理。我尝试了所有其他类型的断开连接等,但这无需进一步的代码即可工作。

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

于 2013-11-19T17:47:51.493 回答