Comment puis-je voir le SQL qui sera généré par une requête ActiveRecord donnée dans Ruby on Rails

J’aimerais voir l’instruction SQL générée par une requête ActiveRecord donnée. Je reconnais que je peux obtenir ces informations à partir du journal après l’émission de la requête, mais je me demande s’il existe une méthode pouvant être utilisée et ActiveRecord Query.

Par exemple:

SampleModel.find(:all, :select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`") 

Je voudrais ouvrir la console irb et appliquer une méthode à la fin qui montrerait le SQL que cette requête va générer, mais pas nécessairement exécuter la requête.

La dernière fois que j’ai essayé de le faire, il n’y avait pas de moyen officiel de le faire. J’ai eu recours à la fonction find et à ses amis pour générer directement leurs requêtes. Il s’agit d’une API privée, ce qui fait que Rails 3 risque fort de le casser totalement, mais pour le débogage, c’est une solution acceptable.

La méthode est construct_finder_sql(options) ( lib/active_record/base.rb:1681 ), vous devrez utiliser send car il est privé.

Edit : construct_finder_sql été supprimé dans Rails 5.1.0.beta1 .

Semblable à celui de Penger, mais fonctionne à tout moment dans la console même après le chargement des classes et la mise en cache de l’enregistreur:

Pour les rails 2:

 ActiveRecord::Base.connection.instance_variable_set :@logger, Logger.new(STDOUT) 

Pour Rails 3.0.x:

 ActiveRecord::Base.logger = Logger.new(STDOUT) 

Pour Rails> = 3.1.0, cela est déjà fait par défaut dans les consoles. Si c’est trop bruyant et que vous souhaitez le désactiver, vous pouvez le faire:

 ActiveRecord::Base.logger = nil 

Collez un des puts query_object.class pour voir quel type d’object vous puts query_object.class , puis recherchez les documents.

Par exemple, dans Rails 3.0, les étendues utilisent ActiveRecord::Relation qui a une méthode #to_sql . Par exemple:

 class Contact < ActiveRecord::Base scope :frequently_contacted, where('messages_count > 10000') end 

Alors, quelque part, vous pouvez faire:

 puts Contact.frequently_contacted.to_sql 

Cela peut être une vieille question mais j’utilise:

 SampleModel.find(:all, :select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit=> 1, :order => '`date`', :group => "`date`" ).explain 

La méthode d’ explain donnera une instruction SQL assez détaillée sur ce qu’elle va faire

Il suffit d’utiliser la méthode to_sql pour générer la requête SQL qui sera exécutée. cela fonctionne sur une relation d’enregistrement active.

 irb(main):033:0> User.limit(10).where(:username => 'banana').to_sql => "SELECT "users".* FROM "users" WHERE "users"."username" = 'banana' LIMIT 10" 

Lorsque vous faites une find , cela ne fonctionnera pas, vous devrez donc append cet identifiant manuellement à la requête ou l’exécuter en utilisant where.

 irb(main):037:0* User.where(id: 1).to_sql => "SELECT "users".* FROM "users" WHERE "users"."id" = 1" 

C’est ce que je fais habituellement pour générer du SQL dans la console

 -> script/console Loading development environment (Rails 2.1.2) >> ActiveRecord::Base.logger = Logger.new STDOUT >> Event.first 

Vous devez le faire lorsque vous démarrez la console pour la première fois, si vous le faites après avoir tapé du code, cela ne semble pas fonctionner

Je ne peux pas vraiment prendre le crédit pour cela, je l’ai trouvé depuis longtemps sur le blog de quelqu’un et je ne me souviens plus de qui il s’agit.

Créez un fichier .irbrc dans votre répertoire personnel et collez-le dans:

 if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER') require 'logger' RAILS_DEFAULT_LOGGER = Logger.new(STDOUT) end 

Cela affichera les instructions SQL dans votre session irb au fur et à mesure.

EDIT: Désolé que cela exécute la requête encore, mais c’est le plus proche que je connaisse.

EDIT: Maintenant, avec arel, vous pouvez construire des étendues / méthodes tant que l’object retourne ActiveRecord :: Relation et appelez .to_sql dessus et cela mettra le sql qui va être exécuté.

Essayez le plugin show_sql . Le plugin vous permet d’imprimer le SQL sans l’exécuter

 SampleModel.sql(:select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`") 

Ma façon typique de voir ce que SQL utilise est d’introduire un “bogue” dans le fichier SQL, puis vous recevrez des messages d’erreur sur le journal (et l’écran Web) qui a le SQL en question. Pas besoin de trouver où va la sortie …

Vous pouvez modifier la méthode de journalisation de la connexion pour générer une exception, empêchant l’exécution de la requête.

C’est un hack total, mais ça semble fonctionner pour moi (Rails 2.2.2, MySQL):

 module ActiveRecord module ConnectionAdapters class AbstractAdapter def log_with_raise(sql, name, &block) puts sql raise 'aborting select' if caller.any? { |l| l =~ /`select'/ } log_without_raise(sql, name, &block) end alias_method_chain :log, :raise end end end 

Dans Rails 3, vous pouvez append cette ligne au fichier config / environnements / development.rb

 config.active_record.logger = Logger.new(STDOUT) 

Il va cependant exécuter la requête. Mais à moitié répondu: