Ruby-on-rails 如何在 rake 任务中强制使用 RAILS_ENV?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1090176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:26:29  来源:igfitidea点击:

How do I force RAILS_ENV in a rake task?

ruby-on-railsrubyrake

提问by Sam Saffron

I have this little rake task:

我有这个小耙子任务:

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

Now, when I execute, it will ignore the RAILS_ENV I tried to hard-code. How do I make this task work as expected

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

回答by Michael Sofaer

For this particular task, you only need to change the DB connection, so as Adam pointed out, you can do this:

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

If your task is more complicated, and you need other aspects of ENV, you are safest spawning a new rake process:

如果您的任务更复杂,并且您需要 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

or

或者

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

回答by yacc

In Rails 3, you'll have to use

在 Rails 3 中,你必须使用

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

instead of

代替

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

回答by Kris

Another option is to check the env and refuse to continue:

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

unless Rails.env.development?
  puts "This task can only be run in development environment"
  exit
end

or ask if they really want to continue:

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

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

回答by Adam Byrtek

The cleanest and simplest solution would be to redefine RAILS_ENV(not ENV['RAILS_ENV'])

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

During the boot process of a Rails application RAILS_ENV is initialized as follows

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

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

The rest of Rails code uses RAILS_ENVdirectly.

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

However, as Michael has pointed out in a comment to his answer, switching RAILS_ENVon the fly can be risky. Another approach would be to switch the database connection, this solution is in fact used by the default db:testtasks

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

ActiveRecord::Base.establish_connection(:test)

回答by ealdent

The best way of course is to specify the environment from the command line when you run the rake task, but if for some reason that's not what you want to do, you can do this:

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

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

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

And that should do the trick.

这应该可以解决问题。

回答by kross

There is some strange code in database_tasks.rb:

有一些奇怪的代码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

It always adds testif env is development. I solved the case of wanting to do a custom db:rebuildtask for simultaneous developmentand testby running developmentfirst, and testsecond. In addition, before running the tasks, I call my set_envmethod which makes sure to set ActiveRecord::Tasks::DatabaseTasks.env, without this, the database connections don't seem to be handled discretely for environments as expected. I tried all other sorts of disconnect etc, but this worked without further code.

test如果 env 是 ,它总是添加development。我解决了想要同时执行自定义db:rebuild任务的情况,development并且首先test运行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


Here is a gist of my full db.rakefile with simultaneous multi-environment db:rebuildand db:truncate

这是我的完整db.rake文件的要点,同时具有多环境db:rebuilddb:truncate