web-dev-qa-db-fra.com

Comment forcer Rails_ENV dans une tâche de râteau?

J'ai cette petite tâche de râteau:

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

Maintenant, lorsque j'exécuterai, il ignorera le Rails_ENV que j'ai essayé de coder en dur. Comment faire pour que cette tâche fonctionne comme prévu

45
Sam Saffron

Pour cette tâche particulière, il vous suffit de modifier la connexion DB, donc comme l'a souligné Adam, vous pouvez le faire:

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 votre tâche est plus compliquée et que vous avez besoin d'autres aspects d'ENV, vous générez le plus sûr un nouveau processus de râteau:

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

ou

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
50
Michael Sofaer

Dans Rails 3, vous devrez utiliser

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

au lieu de

Rails_ENV = "test"
Rake::Task["db:drop"].invoke 
19
yacc

Une autre option est de vérifier l'env et de refuser de continuer:

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

ou demandez s'ils veulent vraiment continuer:

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
11
Kris

La solution la plus propre et la plus simple serait de redéfinir Rails_ENV (ne pas 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

Pendant le processus de démarrage d'une application Rails Rails_ENV est initialisé comme suit

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

Le reste de Rails utilise Rails_ENV directement.

Cependant, comme Michael l'a souligné dans un commentaire à sa réponse, le changement de Rails_ENV à la volée peut être risqué. Une autre approche serait de changer la connexion à la base de données, cette solution est en fait utilisée par la valeur par défaut db:test Tâches

ActiveRecord::Base.establish_connection(:test)
7
Adam Byrtek

La meilleure façon est bien sûr de spécifier l'environnement à partir de la ligne de commande lorsque vous exécutez la tâche de râteau, mais si pour une raison quelconque ce n'est pas ce que vous voulez faire, vous pouvez le faire:

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

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

Et cela devrait faire l'affaire.

4
ealdent

Il y a du code étrange dans 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

Il ajoute toujours test si env est development. J'ai résolu le cas de vouloir effectuer une tâche db:rebuild Personnalisée pour development et test simultanées en exécutant development en premier et test en second . De plus, avant d'exécuter les tâches, j'appelle ma méthode set_env Qui s'assure de définir ActiveRecord::Tasks::DatabaseTasks.env, Sans cela, les connexions à la base de données ne semblent pas être traitées discrètement pour les environnements comme prévu. J'ai essayé toutes les autres sortes de déconnexion, etc., mais cela a fonctionné sans autre code.

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

Voici un aperçu de mon fichier db.rake Complet avec plusieurs environnements simultanés db:rebuild Et db:truncate

3
kross