【问题标题】:Eager loading a custom join with an instance variable渴望使用实例变量加载自定义联接
【发布时间】:2015-08-16 18:42:00
【问题描述】:

给定一个允许用户邀请其他用户参加活动的系统:

class Event
  has_many :invites
end

class User
  has_many :invites
  has_many :invited, inverse_of: :inviter, foreign_key: :inviter_id, class_name: 'Invite'
end

class Invite
  belongs_to :user
  belongs_to :event
  belongs_to :inviter, class_name: 'User'
  has_many :invited, -> (invite) { where(invites: { event_id: invite.event_id }) }, through: :user, class_name: 'Invite'
end

我正在生成一个简单的报告,其中显示了某个活动的所有邀请。我正在尝试修改报告以包含一些可以针对示例事件的invited 执行的操作:

<%- event.includes(:user).each do |invite| -%>
  <%= invite.user.name %>
  <%- invite.invited.each do |other| -%>
    <%= link_to invite_path(other), method: :destroy do %>
      ...
    <% end %>
  <%- end -%>
<%- end -%>

这工作正常,但有一个 N+1 问题。尝试预先加载自定义关联会给出:

弃用警告:关联范围“已邀请”取决于实例(范围块接受参数)。预加载发生在创建单个实例之前。这意味着没有实例被传递到关联范围。这很可能会导致损坏或不正确的行为。这些关联的加入、预加载和预加载已被弃用,将来将被删除。

有没有办法像这样进行急切加载?是否可以给has_many 提供其他提示而不是使用实例变量?

【问题讨论】:

  • 我正在尝试了解您要获取的内容。来自同一用户的邀请参加同一活动?
  • @D-Side 是的,试图获得每个受邀用户的其他邀请。实际的例子要复杂得多,但我尽量简化了这个问题。
  • 嗯,您正在获取每个邀请的邀请集合。这将是一个痛苦,因为它需要一个自连接,而这又需要对所涉及的表实例之一进行别名。所以,Arel 的使用似乎是必须的。
  • 您是否需要按... 嗯... 邀请对邀请进行分组?我的意思是,一个奇怪的排序列表是否足以满足您的需求,还是您需要按相关邀请整齐地分组?

标签: ruby-on-rails ruby


【解决方案1】:

Rails 5 how to form association between tables on multiple shared attributes

您可能需要定义两个不同的关联。一个特定于实例,另一个在连接期间使用。

【讨论】:

    【解决方案2】:

    尝试从事件端使用关系。喜欢:

    class Invite
      belongs_to :user
      belongs_to :event
      belongs_to :inviter, class_name: 'User'
    
      def invited
        event.invites.includes(...)
      end
    end
    

    【讨论】:

    • 基于 OP Invite.invited 查询其他 invites 与邀请具有相同的 inviter(user) 和 event,所以我认为您的查询 event.invites 不够。你能解释更多细节吗?
    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多