Rails ค้นหาเงื่อนไขที่แอตทริบิวต์ไม่ใช่คอลัมน์ฐานข้อมูล

ฉันคิดว่ามันปลอดภัยที่จะบอกว่าทุกคนชอบทำอะไรแบบนี้ใน Rails:

Product.find(:all, :conditions => {:featured => true})

สิ่งนี้จะส่งคืนผลิตภัณฑ์ทั้งหมดที่มีแอตทริบิวต์ "แนะนำ" (ซึ่งเป็นคอลัมน์ฐานข้อมูล) เป็นจริง แต่สมมติว่าฉันมีวิธีการเกี่ยวกับผลิตภัณฑ์ดังนี้:

def display_ready?
     (self.photos.length > 0) && (File.exist?(self.file.path))
end

...และฉันต้องการค้นหาผลิตภัณฑ์ทั้งหมดที่วิธีการนั้นคืนค่าจริง ฉันนึกถึงวิธีที่ยุ่งเหยิงได้หลายวิธี แต่ฉันคิดว่ามันปลอดภัยที่จะบอกว่าเรารัก Rails เพราะสิ่งต่างๆ ส่วนใหญ่ไม่ยุ่งเหยิง

ฉันว่ามันเป็นปัญหาที่พบบ่อยสำหรับฉัน... ฉันจะต้องจินตนาการว่าคำตอบที่ดีจะช่วยคนจำนวนมากได้ มีไอเดียที่ไม่ยุ่งวุ่นวายบ้างไหม?


person tybro0103    schedule 26.08.2010    source แหล่งที่มา


คำตอบ (2)


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

display_ready_products = Product.all.select(&:display_ready?)

สิ่งนี้ไม่มีประสิทธิภาพจนถึงที่สุดโดยเฉพาะอย่างยิ่งหากคุณมีผลิตภัณฑ์จำนวนมากซึ่งอาจไม่เข้าเกณฑ์

วิธีที่ดีกว่าในการทำเช่นนี้คือการมีแคชตัวนับสำหรับรูปภาพของคุณ รวมถึงการตั้งค่าสถานะเมื่อไฟล์ของคุณถูกอัปโหลด:

class Product < ActiveRecord::Base
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :product, :counter_cache => true
end

คุณจะต้องเพิ่มคอลัมน์ลงในตารางผลิตภัณฑ์:

add_column :products, :photos_count, :default => 0

นี่จะทำให้คุณมีคอลัมน์พร้อมจำนวนรูปภาพ มีวิธีเติมตัวเลขที่ถูกต้องไว้ล่วงหน้าที่จุดเริ่มต้นแทนที่จะเป็นศูนย์ แต่ไม่จำเป็นต้องระบุที่นี่

เพิ่มคอลัมน์เพื่อบันทึกแฟล็กไฟล์ของคุณ:

add_column :products, :file_exists, :boolean, :null => false, :default => false

ตอนนี้ทริกเกอร์สิ่งนี้เมื่อบันทึก:

class Product < ActiveRecord::Base
  before_save :assign_file_exists_flag

protected
  def assign_file_exists_flag
    self.file_exists = File.exist?(self.file.path)
  end
end

เนื่องจากแอตทริบิวต์ทั้งสองนี้แสดงผลเป็นคอลัมน์ฐานข้อมูล คุณจึงสามารถสืบค้นคุณลักษณะเหล่านี้ได้โดยตรง:

Product.find(:all, :conditions => 'file_exists=1 AND photos_count>0')

คุณสามารถทำความสะอาดได้โดยการเขียนขอบเขตที่มีชื่อสองขอบเขตที่จะสรุปพฤติกรรมนั้น

person tadman    schedule 26.08.2010
comment
วิธี display_ready ของฉันเป็นเพียงสมมุติฐาน แต่นั่นเป็นคำแนะนำที่ดี! ฉันไม่เคยรู้เกี่ยวกับ counter_cache นอกจากนี้ฉันลืมวิธีการเลือกนั้นไปโดยสิ้นเชิงเช่นกัน ขอบคุณ! - person tybro0103; 26.08.2010
comment
Counter Caching มีประโยชน์มากสำหรับสถานการณ์เช่นนี้ซึ่งคุณต้องการจัดการกับความสัมพันธ์โดยไม่ต้องลงรายละเอียด นอกจากนี้ การแสดงแฟล็กบางส่วนของคุณลงในคอลัมน์ฐานข้อมูลยังทำให้การเลือกทำได้ง่ายมาก และไม่ใช่เรื่องยากเกินไปที่จะเขียนงานเรคเพื่อแก้ไขแฟล็กหากข้อมูลไม่ซิงค์กัน - person tadman; 26.08.2010

คุณต้องทำการเลือกสองระดับ:

1) เลือกแถวที่เป็นไปได้ทั้งหมดจากฐานข้อมูล สิ่งนี้เกิดขึ้นใน db

2) ภายใน Ruby ให้เลือกแถวที่ถูกต้องจากทุกแถว เช่น

possible_products = Product.find(:all, :conditions => {:featured => true})
products = possible_products.select{|p| p.display_ready?}

เพิ่ม:

Or:

products = Product.find(:all, :conditions => {:featured => true}).select {|p|
               p.display_ready?}

การเลือกที่สองคือวิธีการเลือกของวัตถุ Array Select เป็นวิธีที่สะดวกมากพร้อมกับการตรวจหา (การตรวจจับมาจาก Enumerable และผสมกับ Array)

person Larry K    schedule 26.08.2010
comment
ฉันรู้ว่าคุณเป็นคนแรกที่แนะนำวิธีการเลือกซึ่งเป็นสิ่งที่ฉันต้องการ แต่ tadman ก็แค่ให้คำแนะนำที่ดี - person tybro0103; 26.08.2010
comment
ไม่ต้องห่วง. ขอบคุณสำหรับความคิดเห็น ความนับถือ. - person Larry K; 26.08.2010