Besser:
Person.includes(:friends).where( :friends => { :person_id => nil } )
Für das hmt ist es im Grunde dasselbe, Sie verlassen sich auf die Tatsache, dass eine Person ohne Freunde auch keine Kontakte hat:
Person.includes(:contacts).where( :contacts => { :person_id => nil } )
Aktualisieren
Ich habe eine Frage zu has_onein den Kommentaren, also nur aktualisieren. Der Trick dabei ist, includes()dass der Name der Zuordnung whereerwartet wird, aber der Name der Tabelle. Für a wird has_onedie Assoziation im Allgemeinen im Singular ausgedrückt, so dass sich dies ändert, aber der where()Teil bleibt wie er ist. Wenn also Personnur has_one :contactdann Ihre Aussage wäre:
Person.includes(:contact).where( :contacts => { :person_id => nil } )
Update 2
Jemand fragte nach dem Gegenteil, Freunde ohne Menschen. Wie ich unten kommentierte, wurde mir tatsächlich klar, dass das letzte Feld (oben: das :person_id) nicht unbedingt mit dem Modell verknüpft sein muss, das Sie zurückgeben, sondern nur ein Feld in der Verknüpfungstabelle. Sie werden alle nilso sein, dass es jeder von ihnen sein kann. Dies führt zu einer einfacheren Lösung für das oben Gesagte:
Person.includes(:contacts).where( :contacts => { :id => nil } )
Und dann wird es noch einfacher, dies zu ändern, um die Freunde ohne Personen zurückzugeben. Sie ändern nur die Klasse an der Vorderseite:
Friend.includes(:contacts).where( :contacts => { :id => nil } )
Update 3 - Schienen 5
Dank @Anson für die hervorragende Rails 5-Lösung (geben Sie ihm einige +1 für seine Antwort unten) können Sie das left_outer_joinsLaden der Assoziation vermeiden:
Person.left_outer_joins(:contacts).where( contacts: { id: nil } )
Ich habe es hier aufgenommen, damit die Leute es finden, aber er verdient die +1 dafür. Tolle Ergänzung!
Update 4 - Rails 6.1
Vielen Dank an Tim Park für den Hinweis, dass Sie dies in der kommenden Version 6.1 tun können:
Person.where.missing(:contacts)
Dank des Beitrags, auf den er auch verlinkt hat.