Как принудительно включить RAILS_ENV в задаче rake?

У меня есть эта небольшая задача грабли:

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, который я пытался жестко запрограммировать. Как заставить эту задачу работать должным образом


person Sam Saffron    schedule 07.07.2009    source источник


Ответы (6)


Для этой конкретной задачи вам нужно только изменить соединение с БД, поэтому, как указал Адам, вы можете сделать это:

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

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
person Michael Sofaer    schedule 07.07.2009
comment
да, это выглядит немного менее хакерским, чем возиться с RAILS_ENV - person Sam Saffron; 07.07.2009
comment
Для меня вызов дополнительных процессов Rake выглядит гораздо более хакерским. - person Adam Byrtek; 07.07.2009
comment
Это лучше, чем когда ваша задача разрушает окружающую среду. Если вы сделаете это таким образом, вы можете использовать его как зависимость в другой задаче, не вызывая полной катастрофы. Хотите запустить rake task в тестовом режиме? Запустите задачу в тестовом режиме. Попытка подделать тестовый режим, и они, вероятно, вернут все обратно в тот режим, в котором вы на самом деле находитесь, отрывочна. - person Michael Sofaer; 07.07.2009
comment
Я вижу вашу точку зрения. Мне было любопытно, я только что проверил, как это делается в задачах Rails db:test по умолчанию, и похоже, что они не переопределяют RAILS_ENV, а изменяют соединение с базой данных вручную: ActiveRecord::Base.install_connection(:test) - person Adam Byrtek; 08.07.2009
comment
Мне кажется интересным, что для того, чтобы заставить это работать правильно с rake db: reset, мне пришлось использовать системную версию этого ответа. Все остальные с треском провалились, обычно уничтожая мою базу данных разработки. - person wndxlori; 17.06.2014
comment
Мне также пришлось использовать системные вызовы: они были действительно очень медленными. - person C Johnson; 14.07.2016

В Rails 3 вам придется использовать

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

вместо

RAILS_ENV = "test"
Rake::Task["db:drop"].invoke 
person yacc    schedule 30.08.2011

Другой вариант — проверить 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
person Kris    schedule 27.02.2013

Самым чистым и простым решением было бы переопределить 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

Во время процесса загрузки приложения 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)
person Adam Byrtek    schedule 07.07.2009

Лучший способ, конечно, указать среду из командной строки при запуске задачи rake, но если по какой-то причине это не то, что вы хотите сделать, вы можете сделать это:

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

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

И это должно помочь.

person ealdent    schedule 07.07.2009
comment
Вы можете просто require 'config/environment' вместо того, чтобы перезагружать его. - person ealdent; 07.07.2009

В 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 для одновременного выполнения 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

Вот суть моего полного файла db.rake с одновременной мультисредой db:rebuild и db:truncate

person kross    schedule 19.11.2013
comment
Он работал у нас в rails 4 с момента его появления и работает до сих пор. - person kross; 14.07.2016
comment
Спасибо. Хорошо, я сейчас посмотрю на твою суть. - person C Johnson; 14.07.2016