Ruby on rails ActiveRecord-嵌套包含

Ruby on rails ActiveRecord-嵌套包含,ruby-on-rails,ruby,activerecord,associations,Ruby On Rails,Ruby,Activerecord,Associations,我正在尝试在Rails 5中执行以下查询,以便在访问每个事件时不会触发N+1查询。联系人: events = @company.recipients_events .where(contacts: { user_id: user_id }) 我尝试了.includes、.references和.eager_加载的一些组合,但都不起作用。当我访问events.contact时,其中一些返回了SQL错误,而另一些返回了nil对象 以下是我的联想的简要版本: cla

我正在尝试在Rails 5中执行以下查询,以便在访问每个事件时不会触发N+1查询。联系人:

events = @company.recipients_events
                 .where(contacts: { user_id: user_id })
我尝试了.includes、.references和.eager_加载的一些组合,但都不起作用。当我访问events.contact时,其中一些返回了SQL错误,而另一些返回了nil对象

以下是我的联想的简要版本:

class Company
   has_many :recipients
   has_many :recipients_events, through: :recipients, source: :events
end

class Recipient
   belongs_to :contact
   has_many :events, as: :eventable
end

class Event
   belongs_to :eventable, polymorphic: true
end

class Contact
   has_many :recipients
end

实现我所需的正确方法是什么?

如果您在加载@company时已经知道用户id,我会这样做:

@company = Company.where(whatever)
  .includes(recipients: [:recipients_events, :contact])
  .where(contacts: { user_id: user_id })
  .take
events = @company.recipients_events
或者,如果不是:

events = Company.where(whatever)
  .includes(recipients: [:recipients_events, :contact])
  .where(contacts: { user_id: user_id })
  .take
  .recipients_events

ActiveRecord查询计划器将确定它认为获取该数据的最佳方式。如果没有
where
,每个表可能会有一个查询,但是当您链接
includes().where()
时,您可能会得到两个查询,两个查询上都有左外部联接。

我正在使用rails控制台测试的视图代码段是什么您可以尝试使用类似@company.recipients\u events.includes(:contact)的内容吗(联系人:{user\u id:user\u id})。如果有错误,则显示错误:“无法将“事件”加入名为“联系人”的关联;可能是您拼写错误?”。我相信发生这种情况是因为事件与收件人关联,收件人与联系人关联。我还尝试了:@company.recipients\u events.includes(flow\u Recipient::contact)。其中(联系人:{user\u id:user\u id})。在本例中,没有错误,但每次我访问event.contact时,Rails都会对FlowRecipient load和contact load.events=Company.includes(收件人:[:事件,:联系人])执行两个新的查询。其中(id:2,联系人:{user\u id:6}).first.recipients\u事件。当我执行此操作时,Rails会执行两个查询:一个连接所有内容,另一个选择所有公司事件。在此之前,Include似乎一直在工作。但是,当我访问events.first.contact时,Rails会执行另外两个查询:一个用于加载收件人,另一个用于加载联系人。每次我访问新事件,例如events.second.contact。这是预期的行为吗?我想它也会加入或预加载所有收件人和联系人。您要确保
包含将要使用的命名关联。在这种情况下,请尝试将
收件人事件
重组为您的
包含
语句。例如:
events=Company.where(id:2).includes(收件人:[:recipients\u events,:contact]).where(联系人:{user\u id:6}).take.recipients\u events
events=Company.where(id:2).includes(收件人:[:events,:contact]).where(联系人:{user\u id:6}).take.recipients.map(&:events)
作为一个难以辨认的注释,我把它添加到了答案中。