Search code examples
sqlruby-on-railsactiverecordlimithas-many

Rails 5 - Apply limit to eagerly loaded children of collection


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.


Solution

  • 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.