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

Sam*_*ron 45 ruby rake ruby-on-rails

我有这个小耙任务:

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
Run Code Online (Sandbox Code Playgroud)

现在,当我执行时,它将忽略我试图硬编码的RAILS_ENV.如何使此任务按预期工作

Mic*_*aer 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
Run Code Online (Sandbox Code Playgroud)

如果您的任务更复杂,并且您需要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
Run Code Online (Sandbox Code Playgroud)

要么

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
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,调用额外的Rake进程看起来更多*hacky. (2认同)
  • 这比以破坏性的方式让你的任务搞乱环境更好.如果你这样做,你可以将它用作另一个任务的依赖,而不会造成全面的灾难.想在测试模式下运行rake任务吗?在测试模式下运行任务.试图伪造测试模式,他们可能会把它全部改回到你之后实际处理的任何模式都是粗略的. (2认同)
  • 我觉得有趣的是,为了让这个工作正常使用rake db:reset,我必须使用这个答案的"系统"版本.其他人都悲惨地失败了,通常会消灭我的开发数据库. (2认同)

yac*_*acc 19

在Rails 3中,你将不得不使用

Rails.env = "test"
Rake::Task["db:drop"].invoke
Run Code Online (Sandbox Code Playgroud)

代替

RAILS_ENV = "test"
Rake::Task["db:drop"].invoke 
Run Code Online (Sandbox Code Playgroud)


Kri*_*ris 11

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

unless Rails.env.development?
  puts "This task can only be run in development environment"
  exit
end
Run Code Online (Sandbox Code Playgroud)

或者询问他们是否真的想要继续:

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
Run Code Online (Sandbox Code Playgroud)


Ada*_*tek 7

最简洁和最简单的解决方案是重新定义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
Run Code Online (Sandbox Code Playgroud)

在Rails应用程序的引导过程中,RAILS_ENV初始化如下

RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
Run Code Online (Sandbox Code Playgroud)

其余的Rails代码RAILS_ENV直接使用.

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

ActiveRecord::Base.establish_connection(:test)
Run Code Online (Sandbox Code Playgroud)