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