将Arel用于嵌套集&加入查询并转换为ActiveRecord :: Relation

时间:2010-12-21 15:04:17

标签: activerecord ruby-on-rails-3 arel

我有一个组织模型(嵌套集)。我有一个适合人的模特。一个人可以让另一个人担任副手。一个组织由一个人拥有。只有拥有者或其代理人才能看到组织。

我想检索给定人员可见的所有组织,即。所有由该人拥有或由人拥有的组织,其中给定的人是代理人:

o = Arel::Table.new(:organisations)
p = Arel::Table.new(:people)
pd = p.where(p[:id].eq(3).or(p[:deputy_id].eq(3))).project(:id)
op = o.join(p).where(o[:person_id].in(pd)).project("distinct organisations.*)

可能有一种更好的方式来制定最后一次加入,但我想从人们及其副手可见的组织的查询中拆分人和他们的代表的查询。

最后一个连接返回一个Arel :: SelectManager(其中似乎没有任何有用的文档)。

有没有办法将SelectManager转换回ActiveRecord :: Relation,以便从“组合下的闭包”的整个概念中受益?

如何再次在组织上自我加入上述查询,以获取某人或其副手可见的组织的所有后代?我知道SQL但总是失败,SelectManager在组织上进行自我加入。

3 个答案:

答案 0 :(得分:8)

似乎没有任何答案的接受者,我自己找到了解决方法:

1。将最后一次加入转换为ActiveRecord::Relation

Organisation.where(o[:id].in(op))

唯一的问题是这会调用Arel::SelectManager.to_a附带弃用警告(并且也是一项昂贵的操作)。我没有找到替代方案(怀疑没有替代方案,这个弃用警告只是Arel中可观察到的不一致之处,并且它在ActiveRecord中被采用)。

2。嵌套集上的自联接以获取所有后代

o = Organisation.scoped.table
op = Organisation.where(o[:person_id].in(Person.self_and_deputies(person_id).project(:id))).arel
o1 = Arel::Table.new(:organisations, :as => "o1")
o2 = Arel::Table.new(:organisations, :as => "o2")
o3 = o1.join(o2).on(
     o1[:lft].gteq(o2[:lft]).and(
     o1[:rgt].lteq(o2[:rgt]))).where(
     o2[:id].in(op)).project("distinct o1.id")
Organisation.where(o[:id].in(o3))

答案 1 :(得分:4)

您应该可以在join_sources的实例上调用Arel::SelectManager,该实例可以传递给ActiveRecord::Relation#joins。您的查询看起来像这样(未经测试):

o = Organisation.scoped.table
op = Organisation.where(o[:person_id].in(Person.self_and_deputies(person_id).project(:id))).arel
o1 = Arel::Table.new(:organisations, :as => "o1")
o2 = Arel::Table.new(:organisations, :as => "o2")
o3 = Organization.joins(
  o1.join(o2).
    on(o1[:lft].gteq(o2[:lft]).and(o1[:rgt].lteq(o2[:rgt]))).join_sources).
  where(o2[:id].in(op)).
  project("distinct o1.id")

答案 2 :(得分:4)

你也可以这样做:

Organisation.joins(op.join_sql).where(op.where_sql)

我也在搜索了一会儿后得到了这个。这将允许您在其上堆叠任何其他范围。