Reputation: 13328
Say I have the following models:
class Category < ActiveRecord::Base
has_and_belongs_to_many :items
end
class Item < ActiveRecord::Base
has_and_belongs_to_many :categories
end
I'm building an endpoint that retrieves all items, where each item should be coupled with the array of category IDs it belongs to. An example result would be:
[
{
name: 'My Item',
category_ids: [1, 2, 3]
},
// more items...
]
With this configuration, I'm able to call item.category_ids
on each record which results in the SQL that I want, which looks like SELECT categories.id FROM categories INNER JOIN categories_items ... WHERE categories_items.item_id = $1
.
However, that obviously results in an N+1 - and I can't seem to find a way to do this now in an eager load. What I'm looking to do is get a list of items, and just the ID of the categories that they're in, by eager loading the category_ids
field of each Item
(although, if there's another way to accomplish the same using eager loading I'm okay with that as well)
Edit to explain difference from the duplicate:
I'm looking to see if it's possible to do two this in two separate queries. One that fetches items, and one that fetches category IDs. The items table is relatively wide, I'd prefer not to multiply the number of rows returned by the number of categories each item has - if possible.
Upvotes: 1
Views: 839
Reputation: 101811
Using a join model instead of has_and_belongs_to_many
will allow you to query the join table directly instead (without hacking out a query yourself):
class Category < ActiveRecord::Base
has_many :item_categories
has_many :items, through: :item_categories
end
class Item < ActiveRecord::Base
has_many :item_categories
has_many :categories, through: :item_categories
end
class ItemCategory
belongs_to :item
belongs_to :category
end
Note that the table naming scheme for has_many through:
is different - instead of items_categories
its item_categories
. This is so that the constant lookup will work correctly (otherwise rails looks for Items::Category
as the join model!) - so you will need a migration to rename the table.
items = Item.all
category_ids = ItemCategory.where(item_id: items.ids).pluck(:category_id)
Upvotes: 1