Как я могу увидеть SQL, который будет сгенерирован заданным запросом ActiveRecord в Ruby on Rails

Я хотел бы видеть инструкцию SQL, которую генерирует данный запрос ActiveRecord. Я узнаю, что могу получить эту информацию из журнала после того, как запрос был выпущен, но мне интересно, есть ли метод, который можно вызвать, и запрос ActiveRecord.

Например:

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

Я хотел бы открыть консоль irb и применить метод в конце, который покажет SQL, который этот запрос будет генерировать, но не обязательно выполнит запрос.

Ответ 1

Когда в последний раз я пытался это сделать, не было официального способа сделать это. Я прибег к использованию функции, которую find и ее друзья используют для генерации своих запросов напрямую. Это частный API, поэтому существует огромный риск того, что Rails 3 полностью сломает его, но для отладки это хорошее решение.

Метод construct_finder_sql(options) (lib/active_record/base.rb:1681) вам придется использовать send, потому что он является приватным.

Изменить: construct_finder_sql удален в Rails 5.1.0.beta1.

Ответ 2

Подобно penger, но работает в любое время в консоли даже после того, как классы были загружены и журнал был кеширован:

Для Rails 2:

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

Для Rails 3.0.x:

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

Для Rails >= 3.1.0 это уже сделано по умолчанию в консолях. Если это слишком шумно, и вы хотите отключить его, вы можете сделать:

ActiveRecord::Base.logger = nil

Ответ 3

Придерживайтесь puts query_object.class где-нибудь, чтобы посмотреть, с каким типом объекта вы работаете, затем найдите документы.

Например, в Rails 3.0 области применения ActiveRecord::Relation имеют метод #to_sql. Например:

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

Затем вы можете сделать:

puts Contact.frequently_contacted.to_sql

Ответ 4

Это может быть старый вопрос, но я использую:

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

Метод explain даст довольно подробный оператор SQL о том, что он собирается делать

Ответ 5

просто используйте метод to_sql, и он выведет SQL-запрос, который будет запущен. он работает с активным отношением записи.

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

при выполнении find он не будет работать, поэтому вам нужно будет добавить этот идентификатор вручную в запрос или запустить его, используя где.

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

Ответ 6

Создайте файл .irbrc в своем домашнем каталоге и вставьте его в:

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

Это приведет к выводам операторов SQL в ваш сеанс irb, когда вы идете.

EDIT: Извините, что выполнит запрос по-прежнему, но он ближе, чем я знаю.

EDIT: теперь с помощью isl вы можете создавать области/методы до тех пор, пока объект возвращает ActiveRecord:: Relation и вызывается .to_sql на нем, и он выйдет из строя sql, который будет выполнен.

Ответ 7

Это то, что я обычно делаю, чтобы получить SQL, сгенерированный в консоли

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

Это нужно сделать при первом запуске консоли, если вы сделаете это после того, как набрали какой-то код, он не работает

Не могу похвастаться этим, давно нашел его из своего блога и не помню, чей это.

Ответ 8

Попробуйте show_sql plugin. Плагин позволяет печатать SQL без его запуска

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

Ответ 9

Вы можете изменить метод журнала соединений, чтобы создать исключение, не позволяя выполнить запрос.

Это общий взлом, но он работает для меня (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

Ответ 10

Мой типичный способ увидеть, какой sql он использует, - это ввести "ошибку" в sql, после чего вы получите сообщение об ошибках, которое выйдет на обычный журнал (и веб-экран), на котором есть sql. Нет необходимости находить, где идет stdout...

Ответ 11

В Rails 3 вы можете добавить эту строку в конфигурацию /environment/development.rb

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

Однако он выполнит запрос. Но половина получила ответ: