ที่ดีกว่า:
Person.includes(:friends).where( :friends => { :person_id => nil } )
สำหรับ hmt นั้นเป็นสิ่งเดียวกันคุณต้องพึ่งพาความจริงที่ว่าคนที่ไม่มีเพื่อนจะไม่มีที่อยู่ติดต่อ:
Person.includes(:contacts).where( :contacts => { :person_id => nil } )
ปรับปรุง
มีคำถามเกี่ยวกับhas_one
ความคิดเห็นดังนั้นเพียงอัปเดต เคล็ดลับที่นี่คือincludes()
คาดว่าชื่อของสมาคม แต่where
คาดว่าชื่อของตาราง สำหรับhas_one
สมาคมโดยทั่วไปจะแสดงในเอกพจน์ดังนั้นการเปลี่ยนแปลง แต่where()
ส่วนที่อยู่ตามที่เป็นอยู่ ดังนั้นถ้าPerson
เพียงอย่างเดียวhas_one :contact
แล้วคำสั่งของคุณจะเป็น:
Person.includes(:contact).where( :contacts => { :person_id => nil } )
อัปเดต 2
มีคนถามเกี่ยวกับสิ่งที่ตรงกันข้ามเพื่อนที่ไม่มีคน ตามที่ฉันแสดงความคิดเห็นไว้ด้านล่างนี่ทำให้ฉันรู้ว่าฟิลด์สุดท้าย (ด้านบน:person_id
:) ไม่จำเป็นต้องเกี่ยวข้องกับโมเดลที่คุณกำลังจะกลับมา แต่จะต้องเป็นฟิลด์ในตารางเข้าร่วม พวกเขาทั้งหมดจะเป็นไปได้nil
เพื่อที่จะได้เป็นหนึ่งในนั้น สิ่งนี้นำไปสู่การแก้ปัญหาที่ง่ายขึ้นไปด้านบน:
Person.includes(:contacts).where( :contacts => { :id => nil } )
แล้วเปลี่ยนสิ่งนี้เพื่อส่งคืนเพื่อนโดยที่ไม่มีผู้คนกลายเป็นเรื่องง่ายคุณเปลี่ยนชั้นเรียนที่ด้านหน้าเท่านั้น:
Friend.includes(:contacts).where( :contacts => { :id => nil } )
อัพเดท 3 - Rails 5
ขอบคุณ @Anson สำหรับโซลูชัน Rails 5 ที่ยอดเยี่ยม (ให้ +1 แก่เขาสำหรับคำตอบของเขาด้านล่าง) คุณสามารถใช้left_outer_joins
เพื่อหลีกเลี่ยงการโหลดการเชื่อมโยง:
Person.left_outer_joins(:contacts).where( contacts: { id: nil } )
ฉันได้รวมที่นี่เพื่อที่ผู้คนจะพบ แต่เขาสมควรได้รับ +1 สำหรับสิ่งนี้ นอกจากนี้ยอดเยี่ยม!
อัพเดท 4 - Rails 6.1
ขอบคุณTim Park ที่ชี้ให้เห็นว่าใน 6.1 ที่กำลังจะมาถึงคุณสามารถทำได้:
Person.where.missing(:contacts)
ขอบคุณโพสต์ที่เขาเชื่อมโยงด้วย