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