web-dev-qa-db-fra.com

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

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.

110
rswolff

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_sqla été supprimé dans Rails 5.1.0.beta1 .

11
John F. Miller

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
187
gtd

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
82
pathdependent

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.

23
Akshat

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"
17
Itai Sagi

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.

11
penger

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.

10
nitecoder

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 ...

4
rogerdpack

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`")
2
Harish Shetty

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
1
also

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:

0
Timbinous