Hello,
I was wondering if there is an easy way to handle this N+1 problem.
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
def full_name
“comment on #{post.title} by #{author}”
end
end
Now when I want a post with all its comments, I go:
p=Post.find(:first, :include => :comments)
queries:
Post Load Including Associations (0.000863) SELECT posts.“id” AS
t0_r0, posts.“title” AS t0_r1, posts.“body” AS t0_r2, posts.“eated_at”
AS t0_r3, posts.“updated_at” AS t0_r4, comments.“id” AS t1_r0,
comments.“post_id” AS t1_r1, comments.“body” AS t1_r2,
coents.“created_at” AS t1_r3, comments.“updated_at” AS t1_r4 FROM
posts LEFT OUTER JOIN comments ON comments.post_id = posts.id
p.comments.first.full_name
queries:
Post Load (0.000650) SELECT * FROM posts WHERE (posts.“id” = 1)
It seems to me it’s a little dumb to re-get the post, since it’s
already loaded and associated to this comment(since the comment was
loaded through the post’s association).
Ofcourse I could use Post.find(:first, :include => {:comments
=> :post}).
But it doesn’t feel right since Post is included twice.
Any “good” way to do this?
Thanks.
Mathijs
I was wondering if there is an easy way to handle this N+1 problem.
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
def full_name
“comment on #{post.title} by #{author}”
end
end
Now when I want a post with all its comments, I go:
p=Post.find(:first, :include => :comments)
p.comments.first.full_name
Any “good” way to do this?
Well I normally dislike putting text into models. If you want to use
this for printing in a template, you can puts something liek this in a
helper:
def full_name(post)
“comment on #{post.title} by #{post.comments.first.author}”
end
[email protected] wrote:
queries:
Post Load Including Associations (0.000863) SELECT posts.“id” AS
t0_r0, posts.“title” AS t0_r1, posts.“body” AS t0_r2, posts.“eated_at”
AS t0_r3, posts.“updated_at” AS t0_r4, comments.“id” AS t1_r0,
comments.“post_id” AS t1_r1, comments.“body” AS t1_r2,
coents.“created_at” AS t1_r3, comments.“updated_at” AS t1_r4 FROM
posts LEFT OUTER JOIN comments ON comments.post_id = posts.id
p.comments.first.full_name
queries:
Post Load (0.000650) SELECT * FROM posts WHERE (posts.“id” = 1)
Thanks.
Mathijs
I am quite surprised at your findings, I assumed that the association
from comment to post would have been established with the first
collection loading (post to comments).
I will have to try this on my machine tomorrow at work but I assumed
that when an AR collection loads it components, the contained components
automatically get the container id…
ilan
Like I said, this is just a basic ‘proof of concept’.
Ofcourse in this case (almost empty db, sqlite locally) it doesn’t
matter at all, especially not with 1 comment.
And ofcourse putting text should be in a helper, this is just to
demonstrate the strange behavior, the actual case needs different
data(not text) from the parent object.
In real life situations this WILL hurt since it’s a N+1 problem.
If in my example a certain post has 10000 comments, it will generate
10001 queries just for this simple bit of code.
You’re fretting over 0.000650 seconds. Please.