ฉันจะดู SQL ที่จะสร้างโดยแบบสอบถาม ActiveRecord ใน Ruby on Rails ได้อย่างไร


116

ฉันต้องการดูคำสั่ง SQL ที่แบบสอบถาม ActiveRecord จะสร้างขึ้น ฉันรู้ว่าฉันสามารถรับข้อมูลนี้ได้จากบันทึกหลังจากออกแบบสอบถามแล้ว แต่ฉันสงสัยว่ามีวิธีที่สามารถเรียกใช้และแบบสอบถาม ActiveRecord ได้หรือไม่

ตัวอย่างเช่น:

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

ฉันต้องการเปิดคอนโซล irb และใช้เมธอดในตอนท้ายที่จะแสดง SQL ที่แบบสอบถามนี้จะสร้างขึ้น แต่ไม่จำเป็นต้องดำเนินการค้นหา

คำตอบ:


12

เมื่อล่าสุดฉันพยายามทำสิ่งนี้ไม่มีวิธีที่เป็นทางการในการทำ ฉันใช้ฟังก์ชั่นที่findและเพื่อน ๆ ใช้สร้างแบบสอบถามโดยตรง เป็น API ส่วนตัวดังนั้นจึงมีความเสี่ยงอย่างมากที่ Rails 3 จะทำลายมันโดยสิ้นเชิง แต่สำหรับการดีบักมันเป็นวิธีแก้ปัญหาที่โอเค

วิธีการคือconstruct_finder_sql(options)( lib/active_record/base.rb:1681) คุณจะต้องใช้sendเนื่องจากเป็นแบบส่วนตัว

แก้ไข : construct_finder_sql ถูกลบออกใน Rails 5.1.0.beta1


1
นี่ใกล้เคียงกับที่ฉันคิด ฉันเดาว่าคน ๆ หนึ่งสามารถเขียนปลั๊กอินที่จะทำบางสิ่งเช่น: SampleModel.find (: all,: select => "DISTINCT (*)" date,: condition => [" > # {self.date}"],: limit => 1 ,: order => ' date',: group => " date") .show_generated_sql และเรียกสิ่งนี้ว่าเมธอด construction_finder_sql
rswolff

1
ด้วย DataMapper คุณสามารถทำได้เนื่องจากไม่ได้เรียกใช้แบบสอบถามทันที ActiveRecord ในทางกลับกันเรียกใช้แบบสอบถามทันที จะทำหน้าที่ในชุดข้อมูลที่ดึงมาแล้วจากshow_generated_sql find
John

4
ใน Rails 3 construct_finder_sqlจะถูกลบออกอย่างแน่นอน
Veger

190

คล้ายกับ 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

rails consoleนี้จะไม่ทำงานสำหรับฉันใน มันใช้ได้เฉพาะกับ irb ที่โหลดโดยตรงจากเชลล์หรือไม่? (หรือถูกถอดราง 3?)
Eric Hu

2
พวกเขาย้ายไปยังตำแหน่งที่เหมาะสมยิ่งขึ้นสำหรับ Rails 3 ... ดูเวอร์ชันอัปเดตของฉัน
gtd

มีวิธีใดบ้างที่จะทำสิ่งนี้โดยอัตโนมัติทุกครั้งที่เริ่มคอนโซล? บางอย่างเช่นก่อนโหลดเบ็ด?
สตรีม

1
@ stream7 .. ฉันไม่รู้ว่าตอนนี้คุณต้องการสิ่งนี้หรือไม่ แต่คุณสามารถย้ายรหัสนี้ไปที่environment.rb.. ได้if "irb" == $0;ActiveRecord::Base.logger = Logger.new(STDOUT);endจากความคิดเห็นในhttp://weblog.jamisbuck.org/2007/1/8/watching-activerecord-do
-it

สิ่งนี้ไม่ตอบคำถาม: วิธีแสดง sql สำหรับแบบสอบถามเฉพาะในขณะที่ดีบักโดยไม่ต้องเรียกใช้แบบสอบถาม
bradw2k

87

ติดไว้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

3
เหตุใดคำตอบนี้จึงไม่ได้รับการโหวต สำหรับ Rails 3 เป็นคำตอบที่ดีกว่า - คุณสามารถรับผลลัพธ์ของคำสั่ง AR :: Relation ใดก็ได้เพียงแค่ใส่ ".to_sql" ต่อท้าย คำถามนี้ยังให้คำตอบ: stackoverflow.com/questions/3814738/…
Steve Midgley

5
ระวัง: คุณจะไม่ได้รับ SQL ทั้งหมดหากคุณมีincludesความสัมพันธ์
Barry Kelly

3
@BarryKelly ทำไมเป็นอย่างนั้น?
วิษณุ ณ รังค์

25

นี่อาจเป็นคำถามเก่า แต่ฉันใช้:

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

explainวิธีการค่อนข้างจะให้คำสั่ง SQL รายละเอียดเกี่ยวกับสิ่งที่จะทำ


3
นอกจากนี้ยังเรียกใช้การสืบค้นซึ่งอาจไม่ใช่สิ่งที่ผู้คนต้องการเพียงเพื่อการบันทึก
อิบรา

22

เพียงใช้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"

11

นี่คือสิ่งที่ฉันมักจะทำเพื่อให้ SQL สร้างขึ้นในคอนโซล

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

คุณต้องทำสิ่งนี้เมื่อคุณเริ่มคอนโซลครั้งแรกหากคุณทำสิ่งนี้หลังจากที่คุณพิมพ์รหัสบางส่วนดูเหมือนจะไม่ได้ผล

ไม่สามารถให้เครดิตเรื่องนี้ได้จริงๆพบเมื่อนานมาแล้วจากบล็อกของใครบางคนและจำไม่ได้ว่าเป็นใคร


1
ฉันค่อนข้างมั่นใจว่าเป็นบล็อกของ Jamis Buck: weblog.jamisbuck.org/2007/1/8/…
rswolff

1
ฉันไม่แน่ใจว่าเป็นเพราะ Rails 2.3 หรือบางอย่างในสภาพแวดล้อมของฉัน แต่มันไม่ได้ผลสำหรับฉัน ดูคำตอบของฉันด้านล่าง
gtd

นี่เป็นทางออกที่ยอดเยี่ยม IMO
Benjamin Atkin

10

สร้างไฟล์. irbrc ในโฮมไดเร็กทอรีของคุณและวางสิ่งนี้ใน:

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

ที่จะส่งออกคำสั่ง SQL ในเซสชัน irb ของคุณในขณะที่คุณไป

แก้ไข: ขออภัยที่ยังคงดำเนินการค้นหา แต่ใกล้เคียงที่สุดที่ฉันรู้จัก

แก้ไข: ตอนนี้ด้วย arel คุณสามารถสร้างขอบเขต / วิธีการได้ตราบเท่าที่วัตถุส่งคืน ActiveRecord :: Relation และเรียก. to_sql จากนั้นมันจะใส่ sql ที่กำลังจะถูกเรียกใช้งาน


นี่คือสิ่งที่ฉันทำ แต่ฉันสนใจมากกว่าเพียงแค่เห็น SQL ที่คาดการณ์ไว้แบบสอบถาม ActiveRecord จะสร้างขึ้น ฉันแปลกใจที่ไม่มีวิธีง่ายๆในการทำเช่นนี้ ...
rswolff

5

วิธีทั่วไปของฉันในการดูว่า sql ใช้อะไรคือการแนะนำ "bug" ใน sql จากนั้นคุณจะได้รับข้อความแสดงข้อผิดพลาดที่พ่นออกไปยังเครื่องบันทึกปกติ (และหน้าจอเว็บ) ที่มี sql ที่เป็นปัญหา ไม่ต้องหาว่า stdout ไปไหน ...


1
วิธีแก้ปัญหาที่น่าตื่นเต้น แต่รวดเร็วที่สุด :)
JánJanočko

2

ลองshow_sql ปลั๊กอิน ปลั๊กอินช่วยให้คุณสามารถพิมพ์ SQL ได้โดยไม่ต้องเรียกใช้

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

1
ดูเหมือนว่าลิงก์จะเสีย (ข้อผิดพลาด 404) อาจเป็นไปได้ว่า Ryan Bigg ลบปลั๊กอิน
DNNX

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

0

ใน Rails 3 คุณสามารถเพิ่มบรรทัดนี้ใน config / environment / development.rb

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

อย่างไรก็ตามมันจะดำเนินการค้นหา แต่ครึ่งหนึ่งได้รับคำตอบ:

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.