使用 Arel 进行嵌套集合 &连接查询并转换为 ActiveRecord::Relation

发布于 2024-10-08 07:48:33 字数 624 浏览 2 评论 0原文

我有一个组织模型(嵌套集)。我有一个人们的榜样。一个人可以有另一个人作为副手。组织归个人所有。组织仅对其所有者或其代理人可见。

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

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 对组织进行自连接总是失败。

I have a model for organisations (nested set). I have a model for people. A person can have another person as deputy. An organisation is owned by a person. An organisation is only visible to the owning person or their deputy.

I would like to retrieve all organisations visible by a given person, ie. all organisations owned by that person or owned by people, for which the given person is a deputy:

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.*)

There is probably a better way to formulate the last join, but I would like to split the query for people and their deputies from the query of organisations visible to people and their deputies.

The last join returns a Arel::SelectManager (for which there seems no useful documentation anywhere).

Is there a way to convert the SelectManager back into an ActiveRecord::Relation to benefit from the whole concept of "closure under composition"?

How do I self join the above query on organisations again to obtain all descendants of the organisations visible to a person or their deputy? I know the SQL but always fail with the SelectManager to do the self join on organisations.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

魔法唧唧 2024-10-15 07:48:33

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

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

Seems there are no takers for any answer and I've found a solution approach myself:

1. Convert the last join to an ActiveRecord::Relation

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

The only issue with this is that this calls Arel::SelectManager.to_a which comes with a deprecation warning (and is also an expensive operation). I haven't found an alternative though (suspect there is none and this deprecation warning is just one of the inconsistencies observable in Arel and it's adoption in ActiveRecord).

2. Self-join on nested set to get all descendants

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))
爺獨霸怡葒院 2024-10-15 07:48:33

你也可以这样做:

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

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

You could also do:

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

I got this after searching a while too. This will allow you to stack any other scope over it.

幸福不弃 2024-10-15 07:48:33

您应该能够在 Arel::SelectManager 实例上调用 join_sources,该实例可以传递给 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")

You should be able to call join_sources on an instance of Arel::SelectManager, which can be passed to ActiveRecord::Relation#joins. Your query would look like this (untested):

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")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文