活动记录关系合并如何工作?



我试图了解ActiveRecord Relations合并的工作原理,因为似乎缺乏文档和示例。它的文档似乎非常简单,它返回调用对象和合并参数"other"的交集。

我有一个简单的用户类和适当的迁移

class User < ApplicationRecord
...
end

在大多数情况下,合并的行为似乎与我的预期完全一样,但在检查后它的行为出乎意料。如果我建立没有重叠项目的平凡关系,我希望它们的交集将是空关系

relation1 = User.where(id: 1)
relation2 = User.where(id: 2)
relation1.merge(relation2) # returns Relation containing User with id: 2
relation2.merge(relation1) # returns Relation containing User with id: 1

这就是它的短处。我尝试做的更长版本是我使用 Pundit 来设置用户的策略范围,在本例中是属于用户的所有财务帐户。然后在我的控制器中,我按类型(储蓄、支票、信用等(过滤了金融账户的索引操作的路由。因此,我希望用户只看到属于他们的那些过滤的财务帐户,这是两组的交集:1(所有支票账户,2(属于用户的所有金融账户。所以看起来合并应该可以解决问题,但它的工作方式似乎与我预期的不同。

Rails 5.1.6
ruby 2.3.3p222

从我从文档中可以看出的一点点,由于"其他"关系是 ActiveRecord 关系(而不是数组(,因此它不会严格生成交集。相反,它会合并条件。在我的琐碎示例中,由于条件非常相似(即 where(id: ?(,合并过程不会 AND 条件,而是用参数对象的条件替换调用对象的条件。

解决此问题的一种方法是使用 to_a 将参数对象转换为 Array。在这种情况下,相同的合并函数会计算正确的交集。

relation1 = User.where(id: 1)
relation2 = User.where(id: 2)
relation1.merge(relation2.to_a) # returns an empty Array (note: not a Relation)

这样做的缺点是查询不是完全在数据库中完成的,因此效率较低。

这似乎也解释了为什么对于我更复杂的合并,它确实经常按预期工作。更复杂的合并将具有更复杂的条件,这些条件很少相似到足以像在更简单的情况下那样被覆盖/替换。

最新更新