Как я могу увидеть 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)
Однако он выполнит запрос. Но половина получила ответ: