coreyward coreyward - 3 months ago 9
Ruby Question

Rails 3 Conditions on Eager Loaded Association

I'm having trouble with Rails 3 using conditions on an associated table while eager loading. It appears that Rails is applying the condition when it loads the original model data, so it won't load the parent model unless a non-zero number of the child/associated models match the condition. This is easier to explain in code (simplified for example):

@post = Post.includes(:comments).where(:comments => { :approved => true }).find(1)


This would generate a SQL query similar to:

SELECT DISTINCT `posts`.id FROM `posts`
LEFT OUTER JOIN `comments` ON `comments`.`post_id` = `posts`.`id`
WHERE (`comments`.`approved` = 1) AND (`posts`.`id` = '1')
LIMIT 1


In the case that there aren't any comments that meet the
approved = 1
condition, no rows are returned, and thus the Post never gets loaded at all.

What is the right way to load a post and the associated comments eagerly with a condition on the comments?

Update



I'd stil love to hear a better way of doing this, but for now I'm using the following to work around it (works with deeply nested eager loading):

@post = Post.find(1)
@comments = @post.comments.where(:approved => true).all

# allows deeper/more complex nesting without getting into SQL:
@post = Post.includes(:author => [ :websites, :photo ]).find(1)
@comments = @post.comments.includes(:editor).where(:approved => true).all

Answer

Update: There might be some nugget of wisdom in this post on includes vs eager_load vs preload.

I'd still love to hear a better way of doing this, but for now I'm using the following to work around it (works with deeply nested eager loading, unlike using joins):

@post = Post.find(1)
@comments = @post.comments.where(:approved => true).all

# allows deeper/more complex nesting without getting into SQL:
@post = Post.includes(:author => [ :websites, :photo ]).find(1)
@comments = @post.comments.includes(:editor).where(:approved => true).all