Reputation: 107
I have two models has_and_belong_to_many to each other:
class Post < ActiveRecord::Base
has_and_belongs_to_many :tags, :join_table => :tags_posts
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :posts, :join_table => :tags_posts
end
And then I have a query:
@tags = Tag.where(name: ["tag1","tag2","tag3"])
I want to get all the unique posts that have these tags, so I write this ugly code:
@posts = []
@tags.each do |tag|
@posts += tag.posts
end
@posts.uniq!
I guess it's inefficient, and since @posts is an array rather than a "ActiveRecord::Relation", I can't use all the class methods on it directly. Is there a better way to achieve this?
Upvotes: 0
Views: 1068
Reputation: 2125
You could join the two tables using includes
and query on the Post
model rather than Tag
so that you get unique posts.
Post.includes(:tags).where(:tags => { name: %w(tag1 tag2 tag3) })
Upvotes: 1
Reputation: 17392
@tags = Tag.where(name: %w(tag1 tag2 tag3)).includes(:posts)
should do the trick (%w()
creates an array of strings, so no difference). It loads all posts with the tags in one or two queries, whatever is more efficient in AR's view. And then you can do
@posts = @tags.map(&:posts).flatten.uniq
to get the posts. map
calls posts
method on every tag and returns an array with those posts, but since you have an array of arrays, you want to flatten
it.
Upvotes: 2