Reputation: 5552
Here is my code below.
Client has many events with foreign key client_id in 'events' table
has_many :events
In console
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)
But when run following,
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
I am getting N+1 queries, I am missing something.
From answer provided I got clue, I wanted ids of events so I was trying as,
clients.each { |cr| cr.events.ids }
clients.each { |cr| cr.events.pluck(:id) }
So N+1 queries got fired, then I worked out with following and solved,
clients.each { |cr| cr.events.map(&:id) }
I treated Relation as Array and used map
instead of ids
or pluck
and solved, no N+1 query got fired.
Upvotes: 0
Views: 51
Reputation: 1902
If your goal is to fetch event ids use join with pluck
event_ids = Client.where(id: [110,112,113,115]).joins(:events).pluck('events.id')
Upvotes: 2
Reputation: 5313
.count
in case of ActiveRecord Relation will simply run the query. If you change it to .size
, the length of array of eager-loaded items will be checked, which is what you're after.
Upvotes: 1