Meglio:
Person.includes(:friends).where( :friends => { :person_id => nil } )
Per l'hmt è sostanzialmente la stessa cosa, fai affidamento sul fatto che una persona senza amici non avrà contatti:
Person.includes(:contacts).where( :contacts => { :person_id => nil } )
Aggiornare
Hai una domanda has_one
nei commenti, quindi solo l'aggiornamento. Il trucco qui è che si includes()
aspetta il nome dell'associazione ma ilwhere
aspetta il nome della tabella. Per a has_one
l'associazione sarà generalmente espressa al singolare, in modo che cambi, ma la where()
parte rimane così com'è. Quindi, se Person
solo has_one :contact
allora la tua affermazione sarebbe:
Person.includes(:contact).where( :contacts => { :person_id => nil } )
Aggiornamento 2
Qualcuno ha chiesto del contrario, amici senza gente. Come ho commentato di seguito, questo in realtà mi ha fatto capire che l'ultimo campo (sopra: il :person_id
) in realtà non deve essere correlato al modello che stai restituendo, deve solo essere un campo nella tabella di join. Lo saranno tutti, nil
quindi può essere uno di loro. Questo porta a una soluzione più semplice di quanto sopra:
Person.includes(:contacts).where( :contacts => { :id => nil } )
E poi cambiando questo per restituire gli amici senza persone diventa ancora più semplice, cambi solo la classe in primo piano:
Friend.includes(:contacts).where( :contacts => { :id => nil } )
Aggiornamento 3 - Rotaie 5
Grazie a @Anson per l'eccellente soluzione Rails 5 (dategli alcuni +1 per la sua risposta di seguito), potete usare left_outer_joins
per evitare di caricare l'associazione:
Person.left_outer_joins(:contacts).where( contacts: { id: nil } )
L'ho incluso qui, così la gente lo troverà, ma per questo merita i +1. Grande aggiunta!
Aggiornamento 4 - Rotaie 6.1
Grazie a Tim Park per aver sottolineato che nella prossima 6.1 puoi farlo:
Person.where.missing(:contacts)
Grazie al post a cui è collegato anche lui.