# Eager loading not working well for me

**URL:** <https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261>\
**Category:** Rails\
**Created:** [March 27, 2007, 4:39am UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261 "2007-03-27T04:39:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [March 27, 2007, 4:39am UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/1 "2007-03-27T04:39:14Z")

</div>

Man my app is causing me so much grief lately.

Okay let’s say I have:

class Discussion  
has\_many :posts  
end

class Post  
belongs\_to :discussion  
acts\_as\_tree  
end

Then let’s say I grab a discussion object and try to eager load all of  
its posts:

discussion = Discussion.find(:first, :include =\> [:posts])

Seems simple enough and it grabs an entire tree of posts. However:

discussion.posts.first.children

will run a MySQL query instead of (more smartly) simply accessing the  
already eager-loaded posts.

I’m getting pretty aggravated. I’ve been trying to properly handle going  
about my app for ages and nothing seems to work optimally. Any ideas?

More importantly: should I even bother.

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [March 27, 2007, 8:30am UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/2 "2007-03-27T08:30:53Z")

</div>

Eleo wrote:

> discussion = Discussion.find(:first, :include =\> [:posts])
> 
> Seems simple enough and it grabs an entire tree of posts. However:
> 
> discussion.posts.first.children
> 
> will run a MySQL query instead of (more smartly) simply accessing the  
> already eager-loaded posts.

To avoid a query you have to eager load all the levels you’ll be  
accessing:

discussion = Discussion.find(:first, :include =\> {:posts =\> :children})

–  
We develop, watch us RoR, in numbers too big to ignore.

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [March 27, 2007, 12:23pm UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/3 "2007-03-27T12:23:19Z")

</div>

That doesn’t make any sense to me though. When I do  
Dicussion.find(:first, :include =\> [:posts]) I have effectively grabbed  
all the posts, including the children and those children and so on. All  
of the posts, including children, have the same discussion\_id, after  
all.

Another problem with :include =\> {:posts =\> :children} is that it only  
grabs one level of children. I can make the include argument more  
complex but there’s no way to know how deep a tree is.

I’ve found a better way to get children without queries is something  
like:

discussion.posts.collect {|post| if post.parent\_id = num}.compact

Which will grab the children of a certain parent. This of course only  
works if I indeed have an entire tree of posts pre-loaded.

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [March 27, 2007, 8:05pm UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/4 "2007-03-27T20:05:28Z")

</div>

Eleo wrote:

> I’ve found a better way to get children without queries is something  
> like:
> 
> discussion.posts.collect {|post| if post.parent\_id = num}.compact
> 
> Which will grab the children of a certain parent. This of course only  
> works if I indeed have an entire tree of posts pre-loaded.

OK, I didn’t realise discussion.posts contained every post in  
the discussion, rather than just the top-level posts.

Perhaps you should use Better Nested Set:  
[http://opensource.symetrie.com/trac/better\_nested\_set/](http://opensource.symetrie.com/trac/better_nested_set/)

This will allow you to fetch the posts in depth-first order,  
so you can render whole discussion trees without searching,  
sorting, or re-querying.

–  
We develop, watch us RoR, in numbers too big to ignore.

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [April 2, 2007, 3:08am UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/5 "2007-04-02T03:08:35Z")

</div>

I am using better nested set right now, but I don’t see precisely how  
I’m supposed to render without searching/sorting/querying. As it is,  
foo.children or the like will still query the database. Can you  
elaborate on how this is supposed to work, please?

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [April 2, 2007, 5:27am UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/6 "2007-04-02T05:27:58Z")

</div>

Eleo wrote:

> I am using better nested set right now, but I don’t see precisely how  
> I’m supposed to render without searching/sorting/querying. As it is,  
> foo.children or the like will still query the database. Can you  
> elaborate on how this is supposed to work, please?

Fetch all posts using discussion.posts.find(:all, :order =\> ‘lft’),  
then write a recursive rendering function that loops through these,  
watching for the parent\_id to change, increasing the depth by one when  
it changes to the id of the previous object, otherwise popping back up  
the levels until the parent\_ids match.

–  
We develop, watch us RoR, in numbers too big to ignore.

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [April 9, 2007, 10:29pm UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/7 "2007-04-09T22:29:29Z")

</div>

This is the best I could come up with

def show\_thread(posts, parent\_id = nil)  
#result = ‘’  
result = “

\n”  
posts.each do |post|  
if post.parent\_id == parent\_id  
result += “- \n”  
result += render(:partial =\> ‘post’, :object =\> post) + “\n”  
result += show\_thread(posts, post.id) unless posts.select {|p|  
p.parent\_id == post.id }.empty?  
result += “
\n”  
end  
end  
result += ‘
’  
end

It’s a massive waste of CPU ticks since it iterates through the array  
once for every item in the array and uses Array#select each time, but  
everything else I tried wasn’t working. The larger the thread, the  
dumber this method gets. If anyone has anything better please let me  
know.

I tried something along the lines of what you suggested. While I  
figured out how to determine if the depth changed I ultimately couldn’t  
figure out how to close off all the tags properly.

---

<div class="post-metadata">

**Author:** ![eleo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ea5d25/32.png) [@eleo](https://www.ruby-forum.com/u/eleo)\
**Post date:** [April 2, 2007, 5:49am UTC](https://www.ruby-forum.com/t/eager-loading-not-working-well-for-me/90261/8 "2007-04-02T05:49:23Z")

</div>

That makes sense (I think). Thanks.
