Tốt hơn:
Person.includes(:friends).where( :friends => { :person_id => nil } )
Đối với hmt về cơ bản là điều tương tự, bạn dựa vào thực tế là một người không có bạn bè cũng sẽ không có liên hệ:
Person.includes(:contacts).where( :contacts => { :person_id => nil } )
Cập nhật
Có một câu hỏi về has_one
các ý kiến, vì vậy chỉ cần cập nhật. Thủ thuật ở đây là includes()
kỳ vọng tên của hiệp hội nhưng where
kỳ vọng tên của bảng. Đối với một has_one
hiệp hội nói chung sẽ được thể hiện trong số ít, do đó thay đổi, nhưng where()
phần vẫn như cũ. Vì vậy, nếu Person
chỉ has_one :contact
thì tuyên bố của bạn sẽ là:
Person.includes(:contact).where( :contacts => { :person_id => nil } )
Cập nhật 2
Có người hỏi về nghịch đảo, bạn bè không có người. Như tôi đã nhận xét bên dưới, điều này thực sự khiến tôi nhận ra rằng trường cuối cùng (ở trên :person_id
:) không thực sự phải liên quan đến mô hình bạn đang trả về, nó chỉ phải là một trường trong bảng tham gia. Tất cả đều nil
như vậy nên nó có thể là bất kỳ ai trong số họ. Điều này dẫn đến một giải pháp đơn giản hơn cho các điều trên:
Person.includes(:contacts).where( :contacts => { :id => nil } )
Và sau đó chuyển đổi điều này để trả lại những người bạn không có người trở nên đơn giản hơn, bạn chỉ thay đổi lớp ở phía trước:
Friend.includes(:contacts).where( :contacts => { :id => nil } )
Cập nhật 3 - Đường ray 5
Cảm ơn @Anson về giải pháp Rails 5 tuyệt vời (cung cấp cho anh ấy một số +1 cho câu trả lời của anh ấy bên dưới), bạn có thể sử dụng left_outer_joins
để tránh tải liên kết:
Person.left_outer_joins(:contacts).where( contacts: { id: nil } )
Tôi đã đưa nó vào đây để mọi người sẽ tìm thấy nó, nhưng anh ấy xứng đáng được +1 cho điều này. Bổ sung tuyệt vời!
Cập nhật 4 - Đường ray 6.1
Cảm ơn Tim Park đã chỉ ra rằng trong bản 6.1 sắp tới, bạn có thể làm điều này:
Person.where.missing(:contacts)
Nhờ bài đăng mà anh liên kết quá.