views:

32

answers:

3

Using Rails 3, this scope works as would be expected:

      scope :with_posts, lambda {
        joins(:posts).
        select("authors.*, count(posts.id) posts_count").
        group("posts.author_id").
        having("posts_count > 0")
      }

The generated SQL is:

SELECT authors.*, count(posts.id) posts_count FROM `authors` INNER JOIN `posts` ON `posts`.`author_id` = `author`.`id` GROUP BY posts.author_id HAVING posts_count > 0

But its inverse returns no results:

      scope :with_posts, lambda {
        joins(:posts).
        select("authors.*, count(posts.id) posts_count").
        group("posts.author_id").
        having("posts_count < 1")
      }

I'm assuming that authors with zero posts are simply not being selected by line three... so what is the solution?

+1  A: 

Since inner joing SQL is being created it will show up the results with records available in both tables. So try creating outer join and find/count the null values in next table

try outer join

KoolKabin
A: 

I don't know much about this but I would recommend you to have a look at this Railscast

Hope this works for you.

Rohit
+1  A: 

You are correct, the join is excluding all authors with zero posts, what you need is an outer join.

I don't know rails 3 syntax, but in rails 2, you can specify the joins statement with an SQL fragment instead of simply using the relation name.
User.all(:joins => 'outer join posts on users.id = posts.user_id')
Rails 3 must have an equivalent notation, but I never used it so I don't know the exact syntax. This should be the general idea though.

Faisal