Подтвердить что ты не робот

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

4b9b3361

Ответ 1

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

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

Ответ 2

В Rails 3 вам нужно будет использовать

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

вместо

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

Ответ 3

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

Ответ 4

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

ActiveRecord::Base.establish_connection(:test)

Ответ 5

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

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

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

И это должно сделать трюк.

Ответ 6

В 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 second. Кроме того, перед выполнением задач я вызываю свой метод 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