Eager loading not working well for me

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})

Eleo wrote:

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.

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/

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.

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.