Ho trovato una risposta che aveva alcuni esempi utilizzabili per trovare genitori con figli, ma lo stesso non è utilizzabile per trovare genitori senza figli (presumibilmente dal momento che il join li esclude).
scope :with_children, joins(:children).group("child_join_table.parent_id").having("count(child_join_table.parent_id) > 0")
Qualcuno può indicarmi la giusta direzione?
Questo dovrebbe fare il lavoro che desideri:
scope :without_children, includes(:children).where(:children => { :id => nil })
La grande differenza qui è che i joins
diventano un includes
: un include carica tutte le relazioni, se esistono, il join caricherà solo gli oggetti associati e ignorerà l’object senza una relazione.
In effetti, scope :with_children, joins(:children)
dovrebbe essere sufficiente per restituire il Parent con almeno 1 figlio. Provalo!
Vedi la risposta di @ Anson qui sotto
Come ha sottolineato @MauroDias, se si tratta di una relazione autoreferenziale tra genitori e figli, questo codice non funzionerà.
Con un po ‘di ricerca, ho scoperto come farlo:
Considera questo modello:
class Item < ActiveRecord::Base has_many :children, :class_name => 'Item', :foreign_key => 'parent_id'
Come restituire tutti gli articoli senza figli (i):
Item.includes(:children).where(children_items: { id: nil })
Come ho trovato il tavolo children_items
?
Item.joins(:children)
genera il seguente SQL:
SELECT "items".* FROM "items" INNER JOIN "items" "children_items" ON "children_items"."parent_id" = "items"."id"
Quindi ho indovinato che Rails usa un tavolo quando ha bisogno di un JOIN in un caso autoreferenziale.
Domande simili:
@ Mikyahi ha una solida risposta di Rails 4, ma per le persone che arrivano qui con Rails 5 hai più opzioni.
Utilizzando Rails 5:
A partire da Rails 5, puoi anche utilizzare left_outer_joins per evitare di caricare l’associazione. È stato introdotto nella richiesta pull # 12071 .
scope :without_children, left_outer_joins(:children).where(children: { id: nil })
Per i genitori con bambini, la soluzione Rails 4 di MrYoshiji è ancora quella da utilizzare:
scope :with_children, joins(:children)
Ecco come ho risolto per Rails 5:
scope :without_comments, -> do left_outer_joins(:comments).where(comments: { id: nil }) end