2010-08-03 8 views
6

In Rails3 sembra esserci un problema quando concatenando due ambiti (ActiveRelations) che hanno ciascuno un diverso comprendono:problema: activerecord (rails3), concatenamento ambiti con include

Considerare questi due scopi, entrambi i quali funzionano bene per conto proprio:

Prima portata:

scope :global_only, lambda { |user| 
includes(:country) 
.where("countries.area_id <> ?", user.area) } 

Work.global_only (utente) => (distinta di taglio dei campi da SQL per la leggibilità)

SELECT * FROM "works" LEFT OUTER JOIN "countries" ON "countries"."id" = "works"."country_id" WHERE (countries.area_id <> 3) 

Ora la seconda portata:

scope :not_belonging_to, lambda { |user| 
includes(:participants) 
.where("participants.user_id <> ? or participants.user_id is null", user) } 

Work.not_belonging_to (utente) => (distinta di taglio dei campi da SQL per la leggibilità)

SELECT * FROM "works" LEFT OUTER JOIN "participants" ON "participants"."work_id" = "works"."id" WHERE (participants.user_id <> 6 or participants.user_id is null) 

Così sia di quelli lavoro correttamente singolarmente.

Ora, li concatenare insieme:

Work.global_only (utente) .not_belonging_to (utente)

Lo SQL:

SELECT (list of fields) FROM "works" LEFT OUTER JOIN "countries" ON "countries"."id" = "works"."country_id" WHERE (participants.user_id <> 6 or participants.user_id is null) AND (countries.area_id <> 3) 

Come si può vedere, il join dal secondo campo di applicazione viene ignorato del tutto. Pertanto SQL non riesce su "nessuna colonna" partecipanti.utente_id ". Se concatenare gli ambiti nell'ordine inverso, sarà presente l'unione dei partecipanti e l'unione dei paesi verrà persa. È sempre il secondo join perso, a quanto pare.

Ti sembra un bug con ActiveRecord, o sto facendo qualcosa di sbagliato, o si tratta di una "caratteristica" :-)

(PS. Sì, lo so, posso creare un ambito che unisce entrambi tabelle e produrrà correttamente il risultato che desidero, l'ho già fatto, ma stavo cercando di realizzare ambiti più piccoli di quelli che possono essere concatenati in modi diversi, il che dovrebbe essere il vantaggio di activerecord su straight sql.)

+2

Si scopre che questo è un bug; essere rattoppato per la prossima versione di Rails3. –

+0

sì, in questo momento ci vuole solo 1 volta, quindi se vuoi aggirare il problema, crea un nuovo scope che includa entrambi ... include (: country,: participant) ... oops ... mi sono appena reso conto che anche questo è buggy * sospiro * ... mi dispiace – Ingo

risposta

5

Come regola generale, utilizzare :includes per il caricamento agevole e :joins per le condizioni. Nel secondo ambito, l'SQL del join deve essere scritto manualmente perché è richiesto un join sinistro.

Detto questo, provate questo:

scope :global_only, lambda { |user| 
    joins(:country). 
    where(["countries.area_id != ?", user.area]) 
} 

scope :not_belonging_to, lambda { |user| 
    joins("left join participants on participants = #{user.id}"). 
    where("participants.id is null") 
} 

Work.global_only(user).not_belonging_to(user)