Ruby on Rails'de belirli bir ActiveRecord sorgusu tarafından oluşturulacak SQL'i nasıl görebilirim


116

Belirli bir ActiveRecord Sorgusunun üreteceği SQL ifadesini görmek istiyorum. Sorgu yayınlandıktan sonra bu bilgileri günlükten alabileceğimi biliyorum, ancak çağrılabilecek bir yöntem ve ActiveRecord Sorgusu olup olmadığını merak ediyorum.

Örneğin:

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

İrb konsolunu açmak ve sonunda bu sorgunun üreteceği SQL'i gösterecek, ancak sorguyu mutlaka yürütmek zorunda kalmayan bir yöntemi takip etmek istiyorum.

Yanıtlar:


12

Bunu en son yapmaya çalıştığımda bunu yapmanın resmi bir yolu yoktu. Ben findve arkadaşlarının sorgularını doğrudan oluşturmak için kullandıkları işlevi kullanmaya başvurdum . Bu özel bir API olduğundan, Rails 3'ün onu tamamen kırması gibi büyük bir risk vardır, ancak hata ayıklama için uygun bir çözümdür.

Yöntem construct_finder_sql(options)( lib/active_record/base.rb:1681) özel olduğu için kullanmanız gerekecek send.

Düzenleme : construct_finder_sql Rails 5.1.0.beta1'de kaldırıldı .


1
Bu düşündüğüm şeye yakın. Sanırım bir kişi aşağıdaki gibi bir şey yapacak bir eklenti yazabilir: SampleModel.find (: all,: select => "DISTINCT (*)" date,: koşullar => [" > # {self.date}"],: limit => 1 ,: order => ' date',: group => " date") .show_generated_sql ve bunu construct_finder_sql yöntemini çağırın.
rswolff

1
DataMapper ile, sorguyu hemen çalıştırmadığı için yapabilirsiniz. ActiveRecord ise sorguyu hemen yürütür. show_generated_sql, adresinden önceden alınmış bir veri kümesine göre işlem yapacak find.
John F. Miller

4
In Rails 3 construct_finder_sqlgerçekten kaldırıldı
Veger

190

Penger'inkine benzer, ancak sınıflar yüklendikten ve kaydedici önbelleğe alındıktan sonra bile konsolda her zaman çalışır:

Raylar 2 için:

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

Rails 3.0.x için:

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

Rails> = 3.1.0 için bu, konsollarda varsayılan olarak zaten yapılır. Çok gürültülü olması ve kapatmak istemeniz durumunda şunları yapabilirsiniz:

ActiveRecord::Base.logger = nil

Bu benim için çalışmıyor rails console. Yalnızca doğrudan kabuktan yüklenen irb için mi çalışıyor? (yoksa raylar 3 için mi kaldırıldı?)
Eric Hu

2
Onu Rails 3 için daha mantıklı bir yere taşıdılar ... güncellenmiş versiyonuma bakın.
gtd

Konsolu her başlattığımda bunu otomatik olarak yapmanın bir yolu var mı? Ön yükleme kancası gibi bir şey mi?
stream7

1
@ stream7..Buna şimdi ihtiyacınız olup olmadığını bilmiyorum, ancak bu kodu şuraya taşıyabilirsiniz environment.rb.. .. if "irb" == $0;ActiveRecord::Base.logger = Logger.new(STDOUT);endbunu http://weblog.jamisbuck.org/2007/1/8/watching-activerecord-do'daki
rubyprince

Bu soruya cevap vermez: Sorguyu çalıştırmadan hata ayıklama yaparken belirli bir sorgu için sql nasıl gösterilir.
bradw2k

87

Yapıştır puts query_object.classNe tür bir nesneyle çalıştığınızı görmek için yere yapıştırın, ardından dokümanları arayın.

Örneğin, Rails 3.0'da, metodu ActiveRecord::Relationolan kapsamlar kullanılır #to_sql. Örneğin:

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

Sonra yapabileceğiniz bir yerde:

puts Contact.frequently_contacted.to_sql

3
Bu yanıt neden olumlu oylanmadı? Rails 3 için bu çok daha iyi bir cevap - herhangi bir AR :: Relation ifadesinin sonuçlarını sonuna ".to_sql" koyarak alabilirsiniz. Bu soru aynı zamanda şu yanıtı sağlar: stackoverflow.com/questions/3814738/…
Steve Midgley

5
Dikkat: Bir includesilişkiniz varsa tüm SQL
Barry Kelly

3
@BarryKelly Neden böyle?
Vishnu Narang

25

Bu eski bir soru olabilir ama kullanıyorum:

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

explainYöntem onun ne yapacak oldukça detaylı SQL deyimi verecek


3
Ayrıca, yalnızca kayıt için insanların istediği şey olmayan sorguyu da çalıştırır.
İbrahim

22

sadece to_sqlyöntemi kullanın ve çalıştırılacak sql sorgusunu çıkaracaktır. aktif bir kayıt ilişkisi üzerinde çalışır.

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

yaptığınızda findişe yaramaz, bu nedenle bu kimliği sorguya manuel olarak eklemeniz veya nerede kullanarak çalıştırmanız gerekir.

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

11

Konsolda oluşturulan SQL'i almak için genellikle yaptığım şey bu

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

Konsolu ilk başlattığınızda bunu yapmak zorundasınız, bunu bir kod yazdıktan sonra yaparsanız, çalışmıyor gibi görünüyor.

Bunun için gerçekten itibar alamıyorum, uzun zaman önce birinin blogundan buldum ve kimin olduğunu hatırlayamıyorum.


1
Jamis Buck'ın blogu olduğundan oldukça eminim: weblog.jamisbuck.org/2007/1/8/…
rswolff

1
Bunun Rails 2.3'ten mi yoksa çevremdeki bir şeyden mi kaynaklandığından emin değilim, ancak bu benim için çalışmıyor. Aşağıdaki cevabıma bakın.
gtd

Bu harika bir çözüm IMO'dur.
Benjamin Atkin

10

Ana dizininizde bir .irbrc dosyası oluşturun ve bunu şuraya yapıştırın:

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

Bu, siz ilerledikçe irb oturumunuza SQL ifadelerini çıkaracaktır.

DÜZENLEME: Maalesef sorguyu yine de çalıştıracak, ancak en yakın bildiğim bu.

DÜZENLEME: Artık arel ile, nesne ActiveRecord :: Relation döndürdüğü ve üzerinde .to_sql çağrısı yaptığı ve yürütülecek sql'yi çıkardığı sürece kapsamları / yöntemleri oluşturabilirsiniz.


Yaptığım şey bu, ancak ActiveRecord sorgusunun oluşturacağı öngörülen SQL'i görmekle daha çok ilgileniyorum. Bunu yapmanın basit bir yolu olmadığına şaşırdım ...
rswolff

5

Kullandığım sql'yi görmenin tipik yolu, sql'de bir "bug" oluşturmaktır, ardından söz konusu sql'nin bulunduğu normal logger'a (ve web ekranına) tükenen bir hata mesajı alırsınız. Standartların nereye gittiğini bulmaya gerek yok ...


1
Muhteşem ama en hızlı çözüm :)
Ján Janočko

2

Show_sql eklentisini deneyin . Eklenti, SQL'i çalıştırmadan yazdırmanızı sağlar

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

1
Bağlantı kopmuş gibi görünüyor (404 hatası). Muhtemelen, Ryan Bigg eklentiyi sildi.
DNNX

1

Bir istisna oluşturmak için bağlantının günlük yöntemini değiştirebilir ve sorgunun çalıştırılmasını engelleyebilirsiniz.

Bu tam bir hack, ancak benim için çalışıyor gibi görünüyor (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

Rails 3'te bu satırı config / environment / development.rb'ye ekleyebilirsiniz.

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

Ancak sorguyu yürütecektir. Ama yarısı cevaplandı:

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.