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.

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 .


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

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

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


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"

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.


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.


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


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`")

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

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ź:

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.