Rails 3 Limiting Included Objects
Asked Answered
S

2

16

For example I have a blog object, and that blog has many posts. I want to do eager loading of say the first blog object and include say the first 10 posts of it. Currently I would do @blogs = Blog.limit(4) and then in the view use @blogs.posts.limit(10). I am pretty sure there is a better way to do this via an include such as Blog.include(:posts).limit(:posts=>10). Is it just not possible to limit the number of included objects, or am I missing something basic here?

Sergent answered 16/7, 2011 at 19:59 Comment(4)
See #6076892Watercraft
Odd, I can't even get this approach to work in the Rails(3.1) console. added has_many :recent_posts, :class_name => 'Post', :limit => 3. But when I do Blog.includes(:posts).first I still got all the posts not just the first 3.Sergent
Try Blog.includes(:recent_posts).first.recent_postsWatercraft
You're right, it doesn't work for me either. The limit is not applied to the query for posts. Odd.Watercraft
W
10

Looks like you can't apply a limit to :has_many when eager loading associations for multiple records.

Example:

class Blog < ActiveRecord::Base
  has_many :posts, :limit => 5
end

class Post < ActiveRecord::Base
  belongs_to :blog
end

This works fine for limiting the number of posts for a single blog:

ruby-1.9.2-p290 :010 > Blog.first.posts
  Blog Load (0.5ms)  SELECT `blogs`.* FROM `blogs` LIMIT 1
  Post Load (0.6ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`blog_id` = 1 LIMIT 5

However, if you try to load all blogs and eager load the posts with them:

ruby-1.9.2-p290 :011 > Blog.includes(:posts)
  Blog Load (0.5ms)  SELECT `blogs`.* FROM `blogs` 
  Post Load (1.1ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`blog_id` IN (1, 2)

Note that there's no limit on the second query, and there couldn't be - it would limit the number of posts returned to 5 across all blogs, which is not at all what you want.

EDIT:

A look at the Rails docs confirms this. You always find these things the minute you've figured them out :)

If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects

Watercraft answered 17/7, 2011 at 5:31 Comment(1)
So what to do in this case then?Dreyfus
S
2

You need to limit the number of posts in your blog model like this:

class Blog < ActiveRecord::Base
    has_many :included_posts, :class_name => 'Post', :limit => 10
    has_many :posts
end

So then you can do:

$ Blog.first.included_posts.count
=> 10
$ Blog.first.posts.count 
=> 999
Sidelong answered 16/7, 2011 at 20:3 Comment(4)
But wouldn't that limit the total number of posts per blog?Sergent
Right, but you can create multiple has many associations. See code.Sidelong
I see how that works, but is it possible to also get the blog object back within the query? @blogs = Blog.limit(3).recent_posts actually gives me an array of Posts, but not the initial parent Blog. I'm trying to optimize my db/query usage if that makes any sense.Sergent
blog = Blog.find(3).include(:included_posts)Curarize

© 2022 - 2024 — McMap. All rights reserved.