Oleksandr Verhun
Oleksandr Verhun

Reputation: 854

query filtering with Rails has_many through

I have a simple question on RoR about many to many relationship(has_many through:). So I have a Tweet model, which has many Tag and vice versa.

You have an index action and view, where you show all tweets with tags, but you also have filtering by tags. Also there's a little detail, that a Tweet can be without a tag.

So if I do something like this:

Tweet.includes(:tags).where(tags: { name: #2017 })

If you then filter, you'll get only the tag, that you filtered, but not all the tags, that there was for Tweet. F.e. if Tweet had tags #2017, #2016, #2015, in the end you'll get only #2017 in your view.

So you can fix the problem with doing something like this:

Tweet.joins(:tags).where(tags: { name: #2017 })

Then you'll get all tags for every tweet.

But the problem is that, if index page has no filters, I want all tweets to show, event without a tag.

Of course you can do a hack like checking if tag param exists do Tweet.joins else do Tweet.includes.

Are there a way to do this within 1 query and without hacks? Also what's the mechanics behind this. I understand the logic behind includes or LEFT OUTER JOIN, because it just maps tweet_id and ’tag_id’ in your intermediate table and then this id to Tag table, when you have something like where query mentioned upper. But, why with INNER JOIN it keeps me giving all tags, gives me question.

Thanks for answering.

Upvotes: 1

Views: 525

Answers (1)

Sapna Jindal
Sapna Jindal

Reputation: 422

Its because includes does the eager loading, when you query

Tweet.includes(:tags).where(tags: {name: "2017"})

It eager loads all the tweets with tags name as 2017. Tweet.tags will not run the db query again and will have only one value for tags.

But in case of joins

Tweet.joins(:tags).where(tags: {name: "2017"})

It does the innner join, and find only those tweets which have tags and tag name is 2017. After finding the tweets when you do Tweet.tags, it runs the db query again to find all the associated tags which gives you the desired result.

Upvotes: 2

Related Questions