2009-08-27 2 views
96

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

Например:

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

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

ответ

11

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

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

Редактировать: construct_finder_sqlwas removed in Rails 5.1.0.beta1.

+1

Это близко к тому, что я думаю. Я думаю, что человек мог бы написать плагин, который бы сделал что-то вроде: SampleModel.find (: all,: select => "DISTINCT (*)",: conditions => ["' date'> # {self.date} "],: limit => 1,: order => '' date'',: group => "' date' "). show_generated_sql и вызовите этот метод методом construct_finder_sql. – rswolff

+1

С DataMapper вы могли бы, потому что он не запускает запрос сразу. ActiveRecord, с другой стороны, выполняет запрос немедленно. 'show_generated_sql' будет действовать на уже извлеченный набор данных из' find'. –

+4

В Rails 3 'construct_finder_sql' действительно удален – Veger

9

Создать .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, который будет выполнен.

+0

+1 за героические усилия – MattC

+0

Это то, что я делал, но я больше заинтересован в просто видеть проецируемое SQL запрос ActiveRecord будет генерировать. Я удивлен, что нет простого способа сделать это ... – rswolff

1

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

Это общая хак, но, кажется, работает для меня (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 
9

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

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

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

Не могу поверить в это, нашел его давным-давно чей-то блог и не помню, чей это.

+1

Я уверен, что это был блог Jamis Buck: http://weblog.jamisbuck.org/2007/1/8/watching-activerecord-do-it-s-thing – rswolff

+1

Я не уверен, что это связано с Rails 2.3 или чем-то в моей среде, но это не работает для меня. См. Мой ответ ниже. – gtd

+0

работает для меня, безупречно. даже после ввода некоторого кода. – pungoyal

181

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

Для Rails 2:

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

Для Rails 3.0.x:

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

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

ActiveRecord::Base.logger = nil 
+0

Это не работает для меня в 'rails console'. Он работает только для irb, загружаемого непосредственно из оболочки? (или он был удален для рельсов 3?) –

+2

Они переместили его в более разумное место для Rails 3 ... см. мою обновленную версию. – gtd

+0

Есть ли способ сделать это автоматически каждый раз, когда я запускаю консоль? Что-то вроде крючка перед погрузкой? – stream7

2

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

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

Похоже, что ссылка сломана (ошибка 404). Вероятно, Райан Бигг удалил плагин. – DNNX

69

воткнуть 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 
+2

Почему этот ответ не поддерживается? Для Rails 3 это лучший ответ - вы можете получить результаты любого заявления AR :: Relation, просто положив «.to_sql» в конце. Этот вопрос также дает ответ: http://stackoverflow.com/questions/3814738/how-can-i-get-sql-statement-created-by-activerecordfind-without-actually-execut –

+4

Остерегайтесь: вы не получите все SQL, если у вас есть 'include' в ваших отношениях –

+1

@BarryKelly Почему? –

0

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

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

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

+0

это легкая часть ... –

18

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

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

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

+2

Он также выполнит запрос, который может не быть тем, чего хотят люди, только для записи. – Ibrahim

1

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

11

просто используйте метод 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" 
Смежные вопросы