I need help generating a query that applies a limit to the children of a collection. Here's a simple demonstration of my problem.
Post model
class Post < ApplicationRecord
has_many :comments
end
Comment model
class Comment < ApplicationRecord
belongs_to :post
end
I want to display all posts in a view, including up to 3 comments for each post. I currently have this query
@posts = Post.includes(:comments)
But this of course will fetch all of the comments, instead of only 3 for each. I also thought of this
@posts = Post.all
@comments = Comment.where(post_id: @posts.ids).limit(3) #this will not apply the limit for each post
I have no idea how to do this without causing an N+1 query.
Any help would be appreciated, thanks.
UPDATE
I think I may need to clarify my expected results. I want to execute an activerecord query on posts that will eagerly load three comments for EACH post. so that I get:
3 comments for post with id 1 3 comments for post with id 2 and so on. Is this possible without causing an N+1 query? the simplest but undesired solution would be this:
@posts.each {|post| post.comments.limit(3)}
This would give me my desired results, but would execute a query for each post.
UPDATE
The accepted answer allows you to apply any sort of query conditions to the association, but this conditions are ignored when using includes
. This means that I would still be loading all comments to memory, wasting memory resources. I'd prefer another solution, but there seems to be no way to achieve a perfect solution here.
You can add one new association in post model which will fetch only 3 records of comments
has_many :recent_comments, -> { limit(3) }, class_name: 'Comment'
and in controller
@post = Post.includes(:recent_comments)
it won't generate n + 1 query.