我如何在多态的条件下急切加载和加入?

How can I eager load and join on a condition for a polymorphic?

这是我的模型:

class Team < ApplicationRecord
  has_many :team_permissions
end

class TeamPermission < ApplicationRecord
  belongs_to :team
  belongs_to :permissible, polymorphic: true
end

class User < ApplicationRecord
  has_many :team_permissions, as: :permissible
end

我知道你可以像这样使用 include 来解决你的 N+1 问题:

Team.includes(team_permissions: :permissible)

现在,我只想加入一个条件下的权限。例如,如果它们不属于一组 id,那么我希望它能工作,但会引发错误。

ActiveRecord:

Team.includes(team_permissions: :permissible).where.not(team_permissions: { id: team_permission_ids })

Error:

ActionView::Template::Error (Cannot eagerly load the polymorphic association :permissible):

进一步研究,我发现下面的方法按照我想要的方式工作,但它没有解决 N+1 问题。

Team.includes(:team_permissions).where.not(team_permissions: { id: team_permission_ids })

我如何为 .includes 包含预加载条件?

不幸的是,Active Record 不够聪明(老实说,也不够信任),无法计算出它需要加入第一个 table 才能应用您的条件,而不是第二个。

你应该可以通过稍微明确一点来帮助解决这个问题:

Team.
  includes(:team_permissions).   # or eager_load(:team_permissions).
  preload(team_permissions: :permissible).
  where.not(team_permissions: { id: team_permission_ids }

当没有条件引用 includes tables 时,默认行为是使用 preload,它通过执行单个附加查询来处理 N+1,并且是与多态关联兼容。然而,当发现这样的条件时,all includes 被转换为 eager_load,它在主查询中执行 LEFT JOIN(因此不兼容:无法编写连接到我们甚至还不知道的 tables 的查询。

上面,我已经分离了我们确实想要通过 preload 加载的部分,所以它应该做正确的事情。