Reputation: 1051
I am trying to perform an activerecord query that essentially does the below.
I have 3 models in a many-to-many relationship
class Item < ActiveRecord::Base
has_many :item_modifiers, dependent: :destroy
has_many :modifiers, through: :item_modifiers
end
class ItemModifier < ActiveRecord::Base
belongs_to :item
belongs_to :modifier
end
class Modifier < ActiveRecord::Base
has_many :item_modifiers
has_many :items, through: :item_modifiers
end
Now I want to find all items that have modifiers with IDs 1 and 2
I have tried several things like:
Item.includes(:modifiers).where(modifiers: {id: 1}).where(modifiers: {id: 2})
This fails because it searches for modifiers where ID = 1 AND ID = 2 which is always false.
This also doesn't work
Item.includes(:modifiers).where(modifiers: {id: [1, 2]})
Because this does an IN (1, 2) query so it returns items with modifiers of either 1 or 2. I want items that have any modifiers as long as they have AT LEAST 1 modifier with ID 1 and AT LEAST 1 modifier with ID 2
I seem to be missing something quite simple but I just can't get my head around it.
Thanks in advance.
Upvotes: 0
Views: 182
Reputation: 754
It could like:
Item.joins(:item_modifiers).where("item_modifiers.modifier_id=1 OR
item_modifiers.modifier_id=2").group("items.id").having("COUNT(item_modifiers.id)=2")
If write in plain SQL, it could be:
SELECT I.*, COUNT(IM.id) FROM items as I INNER JOIN item_modifiers AS IM on I.id=IM.item_id
WHERE IM.modifier_id=1 OR IM.modifier_id=2 GROUP BY I.id HAVING COUNT(IM.id)=2
It will get all the items with its modifers' id include 1 and 2. Maybe in different DB, the statement need a slight change.
Upvotes: 1