Question

I have two models, Item and Tag, that have a many-to-many relationship through a model called ItemTag. I want the user to be able to find all items that have ALL of a given set of tags.tag_name. So, the tables look like this:


items

id

...


items_tags

id

item_id

tag_id

...


tags

id

tag_name

...

Suppose I have the following item / tag_name combinations in the db (though the items_tags join table)

item 1: "red", "yellow", "blue"

item 2: "red", "yellow", "orange"

item 3: "red", "orange", "purple"

The user wants to get all Items that are associated with Tag.tag_names "red" and "yellow" (which obviously should return item 1 and item 2). How do I construct this in Rails3? My assumption is that the SQL statement needs to:

1: join items_tags and tags, obtaining all of the items_tags rows that are associated with the tag that has tag_name "red"

2: join that result set again with the tags table, narrowing the result set to those rows associated with the tag with tag_name "yellow"

3: join items with the final result set to get the list of items associated with both tags

Note that the number of tag_names selected is arbitrary. The user may select 1..n tag_names as the criteria, so I need to be able to construct this query dynamically, preferably without having to use raw SQL.

Was it helpful?

Solution

First you need to set the association in the models.

Items

has_many :item_tags
has_many :tags, :through => item_tags

Item_tags

belongs_to :item
belongs_to :tag

Tags

has_many :item_tags
has_many :items, :through => item_tags

Then in your controller you can do this:

red_tag_items = Tag.find_by_name('red').items
yellow_tag_items = Tag.find_by_name('yellow').items

red_yellow_tag_items = red_tag_items & yellow_tag_items

There must be more efficient ways to do this. Would love to find out. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top