Active Record includes with limit?

hi all

Was wondering how you would handle this situation:

# psuedo code - to illustrate the concept
# not technically correct

* parent has_many: children

# # parents_controller.rb
def index
   @parents = Parent.all.includes(:children) 
end

<-- parents/index.html.erb -->
<% @parents.each do |parent| %>
   <%= parent.name   %>
   <%= parent.child.name   %> <-- How can I get the latest child only, given the above query?  -->
   <%#= parent.children.last.name   %> <-- I could drop the includes statement in the query and fire off an additional query like this in the view, but would prefer not to -->
<% end %>
  • As I understand it, if a parent has 500 children, all 500 will be loaded in memory? Many parents may have many children. In this situation though, I would want only the latest child – or perhaps the latest 2 children for each parent – is there any way I can load only a few children in the one query and present them

Am wondering how you folks would handle this type of situation?

Ben

Appreciate your pointers.

1 Like

Hi Ben!

I have had a similar problem…

Maybe this two post can help you…

There are different ways of doing it, and you have different options id you need just one vs more than one record.

I hope this can help you :slightly_smiling_face:

4 Likes

@bhserna Thank you! I will study your links

has_many :children 
has_many :limited_children, -> { limit(3) }, class_name: Child
Parent.includes(:limited_children).each do |parent|
  # only 3 children (max) will be in the limited_children collection
  parent.limited_children.each do |child|
    # use child
  end
end

As far as I understand, this will not work because it will fetch only 3 children in total, instead of 3 children per parent.

I had one example at hand and tried this…

class Post < ActiveRecord::Base
  has_many :comments
  has_many :latest_comments, -> { order(id: :desc).limit(3) }, class_name: "Comment"
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

Post.includes(:latest_comments).limit(10).map do |post|
  post.latest_comments.each do |comment|
    puts comment.body
  end
end

And it actually printed just 3 comments… and execute this sql

Post Load (3.7ms)  SELECT "posts".* FROM "posts" LIMIT 10
Comment Load (35.8ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" IN (...) ORDER BY "comments"."id" DESC LIMIT 3

Yep, you’re right. The limit appears to limit the total children overall, not per parent. I double checked here myself on my own example and it’s the same as you’re showing.

Now that I think about it, it makes sense it does it that way when eager loading.