如何避免 Rails 4 中的预加载问题

How to avoid eagerloading problem in Rails 4

下面是我的代码。

客户端在 'events' table

中有许多带有外键 client_id 的事件

has_many :events

在控制台中

clients = Client.where(id: [110,112,113,115]).includes(:events)
=>  Client Load (0.4ms)  SELECT `clients`.* FROM `clients` WHERE `clients`.`id` IN (110, 112, 113, 115)
    Event Load (0.5ms)  SELECT `events`.* FROM `events` WHERE `events`.`client_id` IN (110, 112, 113, 115)

但是当运行关注时,

clients.each { |cr| cr.events.count }
   (0.4ms)  SELECT COUNT(*) FROM `events` WHERE `events`.`client_id` = 110
   (0.3ms)  SELECT COUNT(*) FROM `events` WHERE `events`.`client_id` = 112
   (0.3ms)  SELECT COUNT(*) FROM `events` WHERE `events`.`client_id` = 113
   (0.3ms)  SELECT COUNT(*) FROM `events` WHERE `events`.`client_id` = 115

我收到 N+1 个查询,我遗漏了一些东西。

更新

从我得到线索的答案中,我想要事件的 ID,所以我正在尝试,

clients.each { |cr| cr.events.ids }
clients.each { |cr| cr.events.pluck(:id) }

所以 N+1 个查询被解雇了,然后我用下面的方法解决了,

clients.each { |cr| cr.events.map(&:id) }

我将关系视为数组并使用 map 而不是 idspluck 并解决了,没有触发 N+1 查询。

.count 在 ActiveRecord 关系的情况下将简单地 运行 查询。如果您将其更改为 .size,将检查预加载项目数组的长度,这就是您所追求的。

如果您的目标是获取事件 ID,请使用 join with pluck

event_ids = Client.where(id: [110,112,113,115]).joins(:events).pluck('events.id')