2010-08-03 11 views
6

En Rails3 parece que hay un problema al encadenar dos ámbitos (ActiveRelations) que tienen cada uno una diferente incluyen:problema: activerecord (rails3), encadenando ámbitos con incluye

Considere estos dos ámbitos, los cuales funcionan bien por su propia cuenta:

Primera alcance:

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

Work.global_only (usuario) => (lista de cortes de campos de SQL para la legibilidad)

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

Ahora el segundo ámbito:

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

Work.not_belonging_to (usuario) => (lista de cortes de campos de SQL para la legibilidad)

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

Así pues, tanto de los que funcionan correctamente de forma individual.

Ahora, encadenarlos juntos:

Work.global_only (usuario) .not_belonging_to (usuario)

El 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) 

Como se puede ver, la unión de la segunda alcance es ignorado por completo. El SQL por lo tanto falla en 'no dicha columna' participants.user_id '. Si encadenó los ámbitos en el orden inverso, la unión de los "participantes" estará presente y la unión de los "países" se perderá. Siempre es la segunda unión la que se pierde, parece.

se ve este como un insecto con ActiveRecord, o estoy haciendo algo mal, o se trata de una "característica" :-)

(PD. Sí, lo sé, lo puede crear un ámbito que une ambas tablas y arrojará correctamente el resultado que quiero. Ya lo tengo. Pero estaba tratando de hacer que los alcances más pequeños que se pueden encadenar juntos de diferentes maneras, lo que se supone que es la ventaja de activerecord en sql recta.)

+2

Resulta que este es un error; siendo parcheado para la próxima versión de Rails3. –

+0

sí, en este momento lleva solo 1 vez, así que si quieres eludir el problema, crea un nuevo alcance que incluya ambos ... incluye (: país,: participante) ... oops ... me acabo de dar cuenta que también tiene errores * suspiro * ... lo siento – Ingo

Respuesta

5

Como regla general, use :includes para carga ansiosa y :joins para condiciones. En el segundo ámbito, el SQL de unión se debe escribir manualmente porque se requiere una combinación a la izquierda.

Dicho esto, intente esto:

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) 
Cuestiones relacionadas