¿Cómo fuerzo a RAILS_ENV en una tarea de rake?

Tengo esta pequeña tarea de 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 

Ahora, cuando ejecuto, ignorará los RAILS_ENV que traté de codificar. ¿Cómo hago que esta tarea funcione como esperaba

Para esta tarea en particular, solo necesita cambiar la conexión de base de datos, por lo que, como señaló Adam, puede hacer esto:

 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 

Si su tarea es más complicada y necesita otros aspectos de ENV, estará más seguro generando un nuevo proceso de 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 

o

 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 

En Rails 3, tendrás que usar

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

en lugar de

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

Otra opción es verificar el env y negarse a continuar:

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

o pregunta si realmente quieren continuar:

 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 

La solución más limpia y simple sería redefinir RAILS_ENV (no 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 

Durante el proceso de inicio de una aplicación Rails RAILS_ENV se inicializa de la siguiente manera

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

El rest del código de Rails usa RAILS_ENV directamente.

Sin embargo, como Michael ha señalado en un comentario a su respuesta, el cambio de RAILS_ENV sobre la marcha puede ser riesgoso. Otro enfoque sería cambiar la conexión de la base de datos, esta solución es de hecho utilizada por las tareas predeterminadas de db:test

 ActiveRecord::Base.establish_connection(:test) 

La mejor forma, por supuesto, es especificar el entorno desde la línea de comando cuando ejecuta la tarea de rake, pero si por algún motivo no es lo que quiere hacer, puede hacer esto:

 ENV["RAILS_ENV"] = 'test' RAILS_ENV.replace('test') if defined?(RAILS_ENV) load "#{RAILS_ROOT}/config/environment.rb" 

Y eso debería hacer el truco.

Hay un código extraño en 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 

Siempre agrega test si env es development . Resolví el caso de querer hacer una tarea de db:rebuild personalizada para el development y la test simultáneos ejecutando primero el development y test segundo. Además, antes de ejecutar las tareas, llamo a mi método set_env , que se asegura de establecer ActiveRecord::Tasks::DatabaseTasks.env , sin esto, las conexiones de la base de datos no parecen manejarse discretamente para entornos como se esperaba. Probé todos los otros tipos de desconexión, etc., pero esto funcionó sin más código.

 def set_env(env) Rails.env = env.to_s ENV['RAILS_ENV'] = env.to_s ActiveRecord::Tasks::DatabaseTasks.env = env.to_s end 

Aquí está una esencia de mi archivo db.rake completo con simultáneo multi-entorno db:rebuild y db:truncate