Je voudrais voir l'instruction SQL qu'une requête ActiveRecord va générer. 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 qui peut être appelée 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 ajouter une méthode à la fin qui montrerait le code 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 faire cela, il n'y avait aucun moyen officiel de le faire. J'ai eu recours à la fonction que find
et ses amis utilisent pour générer leurs requêtes directement. C'est une API privée donc il y a un risque énorme que Rails 3 le casse totalement), mais pour le débogage, c'est une solution correcte.
La méthode est construct_Finder_sql(options)
(lib/active_record/base.rb:1681
) vous devrez utiliser send
car c'est privé.
Éditer : construct_Finder_sql
a été supprimé dans Rails 5.1.0.beta1 .
Semblable à Penger, mais fonctionne à tout moment dans la console, même après le chargement des classes et la mise en cache du consignateur:
Pour 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 voulez le désactiver vous pouvez faire:
ActiveRecord::Base.logger = nil
Coller un puts query_object.class
quelque part pour voir quel type d’objet vous travaillez, puis recherchez la documentation.
Par exemple, dans Rails 3.0, les étendues utilisent ActiveRecord::Relation
qui a un #to_sql
méthode. Par exemple:
class Contact < ActiveRecord::Base
scope :frequently_contacted, where('messages_count > 10000')
end
Ensuite, vous pouvez faire quelque part:
puts Contact.frequently_contacted.to_sql
C'est 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 explain
donnera une déclaration SQL assez détaillée sur ce qu’elle va faire.
utilisez simplement to_sql
méthode et il va sortir 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 utilisez find
, cela ne fonctionnera pas. Vous devrez donc ajouter cet identifiant manuellement à la requête ou l'exécuter à l'aide de l'endroit où.
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 obtenir du SQL généré en 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 en prendre le crédit, cela a été trouvé il y a longtemps sur le blog de quelqu'un et je ne me souviens plus à qui appartient-il.
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 produira des instructions SQL dans votre session irb au fur et à mesure.
EDIT: Désolé, la requête sera toujours exécutée, mais je la connais de près.
EDIT: Maintenant, avec arel, vous pouvez construire des portées/méthodes tant que l’objet retourne ActiveRecord :: Relation et appelez-le .to_sql dessus, ce qui éteindra le sql à exécuter.
Mon moyen habituel de voir ce que SQL utilise il est d’introduire un "bogue" dans SQL, puis vous obtiendrez un message d’erreur envoyé à l’enregistreur normal (et à l’écran Web) qui contient le SQL en question. Pas besoin de savoir où va stdout ...
Essayez le plugin show_sql . Le plugin vous permet d'imprimer le code SQL sans l'exécuter
SampleModel.sql(:select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")
Vous pouvez modifier la méthode de journalisation de la connexion pour générer une exception, empêchant ainsi l'exécution de la requête.
C'est un hack total, mais cela 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 ajouter cette ligne à config/environment/development.rb
config.active_record.logger = Logger.new(STDOUT)
Il va toutefois exécuter la requête. Mais la moitié a obtenu une réponse: