Reputation: 854
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
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