问题:activerecord(rails3),链接范围包含

ins*_*mer 6 activerecord ruby-on-rails arel ruby-on-rails-3

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

考虑这两个范围,这两个范围都可以自行运行:

第一范围:

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

Work.global_only(user)=>(从SQL中删除字段列表以便易读)

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

现在是第二个范围:

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

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)
Run Code Online (Sandbox Code Playgroud)

所以这两者都可以单独运作.

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

Work.global_only(用户).not_belonging_to(用户)

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)
Run Code Online (Sandbox Code Playgroud)

如您所见,第二个范围的连接将被完全忽略.因此,SQL在'无此列'参与者.user_id'上失败.如果我以相反的顺序链接范围,那么"参与者"连接将出现,"国家/地区"连接将丢失.看来,它总是第二次失败.

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

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

Zub*_*bin 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)
Run Code Online (Sandbox Code Playgroud)