6

在 Rails3 中,链接两个范围(ActiveRelations)时似乎存在问题,每个范围都有不同的包括:

考虑这两个范围,它们都可以自己正常工作:

第一范围:

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

Work.global_only(user) => (为了便于阅读,从 SQL 中截取字段列表)

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

现在是第二个范围:

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

Work.not_belonging_to(user) =>(为了便于阅读,从 SQL 中截取字段列表)

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

因此,这两个都可以单独正常工作。

现在,将它们链接在一起:

Work.global_only(user).not_belonging_to(user)

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)

如您所见,来自第二个作用域的连接完全被忽略了。因此,SQL 在“没有这样的列“participants.user_id”上失败。如果我以相反的顺序链接范围,则将出现“参与者”加入,而“国家”加入将丢失。似乎总是第二次加入丢失。

这看起来像 ActiveRecord 的错误,还是我做错了什么,或者这是一个“功能”:-)

(PS。是的,我知道,我可以创建一个连接两个表的范围,它会正确产生我想要的结果。我已经有了。但我试图制作更小的范围,而不是可以以不同的方式链接在一起,这应该是activerecord优于直接sql的优势。)

4

1 回答 1

5

作为一般规则,:includes用于急切加载和:joins条件。在第二个作用域中,连接 SQL 必须手动编写,因为需要左连接。

也就是说,试试这个:

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)
于 2011-04-05T08:02:52.717 回答