Jak mogę zobaczyć SQL, który zostanie wygenerowany przez dane zapytanie ActiveRecord w Ruby on Rails

116

Chciałbym zobaczyć instrukcję SQL, którą wygeneruje dane zapytanie ActiveRecord. Rozumiem, że mogę uzyskać te informacje z dziennika po wysłaniu zapytania, ale zastanawiam się, czy istnieje metoda, którą można wywołać i kwerendę ActiveRecord.

Na przykład:

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

Chciałbym otworzyć konsolę irb i na końcu przypisać metodę, która pokaże SQL, które wygeneruje to zapytanie, ale niekoniecznie wykona zapytanie.

rswolff
źródło

Odpowiedzi:

12

Kiedy ostatnio próbowałem to zrobić, nie było oficjalnego sposobu, aby to zrobić. Użyłem funkcji, której findi jej przyjaciele używają do bezpośredniego generowania zapytań. Jest to prywatne API, więc istnieje ogromne ryzyko, że Rails 3 całkowicie go zepsuje, ale do debugowania jest to dobre rozwiązanie.

Metoda to construct_finder_sql(options)( lib/active_record/base.rb:1681), której będziesz musiał użyć, sendponieważ jest prywatna.

Edycja : construct_finder_sql została usunięta w Railsach 5.1.0.beta1 .

John F. Miller
źródło
1
To jest blisko tego, o czym myślę. Myślę, że ktoś mógłby napisać wtyczkę, która zrobiłaby coś takiego: SampleModel.find (: all date,: select => "DISTINCT (*)" ,: conditions => [" > # {self.date}"],: limit => 1 ,: order => ' date',: group => " date") .show_generated_sql i wywołaj metodę construct_finder_sql.
rswolff
1
Dzięki DataMapper możesz to zrobić, ponieważ nie uruchamia zapytania od razu. Z drugiej strony ActiveRecord wykonuje zapytanie natychmiast. show_generated_sqlbędzie działać na już pobranym zbiorze danych z find.
John F. Miller
4
W Rails 3 construct_finder_sqlrzeczywiście został usunięty
Veger
190

Podobne do pengera, ale działa w konsoli w dowolnym momencie, nawet po załadowaniu klas i zbuforowaniu rejestratora:

Dla szyn 2:

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

Dla Rails 3.0.x:

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

Dla Railsów> = 3.1.0 jest to już zrobione domyślnie w konsolach. Jeśli jest zbyt głośny i chcesz go wyłączyć , możesz zrobić:

ActiveRecord::Base.logger = nil
gtd
źródło
To nie działa na mnie rails console. Czy działa tylko dla irb ładowanego bezpośrednio z powłoki? (czy też został usunięty z torów 3?)
Eric Hu
2
Przenieśli go w bardziej rozsądne miejsce dla Rails 3 ... zobacz moją zaktualizowaną wersję.
gtd
Czy istnieje sposób, aby zrobić to automatycznie za każdym razem, gdy uruchamiam konsolę? Coś jak hak przed załadowaniem?
stream7
1
@ stream7..Nie wiem, czy potrzebujesz tego teraz, ale możesz przenieść ten kod do environment.rb... if "irb" == $0;ActiveRecord::Base.logger = Logger.new(STDOUT);end..zapomniałem to z komentarzy w http://weblog.jamisbuck.org/2007/1/8/watching-activerecord-do -it-s-thing
rubyprince
To nie odpowiada na pytanie: jak wyświetlić sql dla konkretnego zapytania podczas debugowania bez uruchamiania zapytania.
bradw2k
87

Trzymać puts query_object.classgdzieś zobaczyć, jaki rodzaj obiektu Twój pracy z, a następnie odnośnika docs.

Na przykład w Railsach 3.0 zakresy używają metody, ActiveRecord::Relationktóra ma #to_sqlmetodę. Na przykład:

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

Następnie gdzieś możesz zrobić:

puts Contact.frequently_contacted.to_sql
zależna ścieżka
źródło
3
Dlaczego ta odpowiedź nie jest przegłosowana? Dla Rails 3 jest to o wiele lepsza odpowiedź - możesz otrzymać wyniki dowolnej instrukcji AR :: Relation, umieszczając po prostu ".to_sql" na końcu. To pytanie również dostarcza odpowiedzi: stackoverflow.com/questions/3814738/ ...
Steve Midgley
5
Uwaga: nie dostaniesz wszystkich SQL jeśli masz includesw swoim związku
Barry Kelly
3
@BarryKelly Dlaczego tak jest?
Vishnu Narang
25

To może być stare pytanie, ale używam:

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

explainMetoda daje dość szczegółową instrukcję SQL na co jej zrobi

Akszat
źródło
3
Uruchomi również zapytanie, które może nie być tym, czego chcą ludzie, tylko dla rekordu.
Ibrahim
22

po prostu użyj to_sqlmetody, a wyświetli zapytanie sql, które zostanie uruchomione. działa na relacji rekordu aktywnego.

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

jeśli to zrobisz find, nie zadziała, więc musisz ręcznie dodać ten identyfikator do zapytania lub uruchomić go za pomocą where.

irb(main):037:0* User.where(id: 1).to_sql
=> "SELECT "users".* FROM "users"  WHERE "users"."id" = 1"
Itai Sagi
źródło
11

To jest to, co zwykle robię, aby wygenerować SQL w konsoli

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

Musisz to zrobić przy pierwszym uruchomieniu konsoli, jeśli zrobisz to po wpisaniu kodu, wydaje się, że nie działa

Nie mogę tego przypisać, znalazłem to dawno temu na czyimś blogu i nie pamiętam, kto to jest.

penger
źródło
1
Jestem prawie pewien, że to był blog Jamisa
rswolff
1
Nie jestem pewien, czy jest to spowodowane Railsami 2.3 czy czymś w moim środowisku, ale to nie działa dla mnie. Zobacz moją odpowiedź poniżej.
gtd
To świetne rozwiązanie IMO.
Benjamin Atkin
10

Utwórz plik .irbrc w swoim katalogu domowym i wklej go w:

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

Spowoduje to wyświetlenie instrukcji SQL w sesji irb.

EDYCJA: Przepraszam, że nadal wykona zapytanie, ale jest najbliższe, o którym wiem.

EDYCJA: Teraz z arel, możesz budować zakresy / metody tak długo, jak obiekt zwraca ActiveRecord :: Relation i wywołuje na nim .to_sql, a wyjdzie sql, który ma zostać wykonany.

nitecoder
źródło
Właśnie to robiłem, ale bardziej interesuje mnie po prostu zobaczenie przewidywanego kodu SQL, które wygeneruje zapytanie ActiveRecord. Jestem zaskoczony, że nie ma na to prostego sposobu ...
rswolff
5

Moim typowym sposobem sprawdzenia, jakiego sql używa, jest wprowadzenie "błędu" do sql, wtedy otrzymasz komunikaty o błędach wypluwane do normalnego rejestratora (i ekranu WWW), który ma problem z sql. Nie ma potrzeby, aby dowiedzieć się, dokąd zmierza stdout ...

rogerdpack
źródło
1
Spektakularne, ale najszybsze rozwiązanie :)
Ján Janočko
2

Wypróbuj wtyczkę show_sql . Wtyczka umożliwia drukowanie kodu SQL bez uruchamiania go

SampleModel.sql(:select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")
Harish Shetty
źródło
1
Wygląda na to, że łącze zostało zerwane (błąd 404). Prawdopodobnie Ryan Bigg usunął wtyczkę.
DNNX,
1

Możesz zmienić metodę dziennika połączenia, aby zgłosić wyjątek, uniemożliwiając uruchomienie zapytania.

To totalny hack, ale wydaje mi się, że działa dla mnie (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
również
źródło
0

W Railsach 3 możesz dodać tę linię do config / environment / development.rb

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

Jednak wykona zapytanie. Ale połowa dostała odpowiedź:

Timbinous
źródło