Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting all children of collection with has_many relationship

If I have a collection of Posts, is there anyway to get all Comments for all of those posts using method chaining or scopes?

For example:

posts = Post.where(published: true)
comments = posts.comments

# vs 
comments = []
posts.each do |post|
  comments.push(post.comments)
end
like image 605
you786 Avatar asked Sep 17 '15 20:09

you786


1 Answers

Sure, there are a few ways. You can can use map and flatten, which is fine for a small number of records. Make sure you load the comments in bulk by using includes.

Post.where(published: true).includes(:comments).map(&:comments).flatten

Or you can use a join. This puts more work on the database, which is likely faster, but depends on your schema and dataset. You will typically want to use uniq to prevent duplicates.

posts = Post.where(published: true)
Comment.joins(:post).merge(posts).uniq

Also, make sure that you fully qualify any explicit fragments in any clauses on joined tables, e.g. use where('posts.created_at < ?', ...) instead of where('created_at < ?', ...).

Edit:

Another variant on the first, in case you want to return a relation (which can be further scoped down the line):

Comment.where(id: Post.where(published: true).pluck(:id))
like image 157
ahmacleod Avatar answered Oct 29 '22 01:10

ahmacleod