Reputation: 19723
An article has 1 or many comments. How would I get only the articles with 0 comments?
This would be easier with a counter cache. However, I need to do this without using a counter cache.
Upvotes: 1
Views: 66
Reputation: 7273
class Article < ActiveRecord::Base
has_many :comments
scope :without_comments,
joins(<<-SQL
LEFT OUTER JOIN
(SELECT article_id
FROM comments GROUP BY article_id) AS rolled_up_comments
ON comments.article_id = articles.id
SQL
).
where("rolled_up_comments.article_id" => nil)
end
Use like this:
Article.without_comments.all
This could easily be adapted to return articles with a specific number or range of comments, e.g.:
class Article < ActiveRecord::Base
has_many :comments
scope :with_comment_count,
joins(<<-SQL
LEFT OUTER JOIN
(SELECT article_id, COUNT(*) AS comment_count
FROM comments GROUP BY article_id) AS rolled_up_comments
ON comments.article_id = articles.id
SQL
)
scope :with_n_comments, lambda {
with_comment_count.
where(:"rolled_up_comments.comment_count" => n)
}
end
In the latter case, n
can be a specific number, like 100, or a range like 1..10
which ActiveRecord will turn into a BETWEEN
query returning articles with 1 through 10 comments.
Note that in the 0-comment case, the count is NULL
, so you can't use the range query for that.
I've tested this in Postgres. I don't know if it'll work in MySQL. I'm not sure how/if MySQL handles sub-selects for joins.
Edit: The solution pointed out by a previous commenter is easier, if you only need to know articles without comments. For count ranges, the above will work.
Upvotes: 1
Reputation: 841
I'm interested by the answer.
Did you try with a scope?
I'm not sure but it could be the solution.
Rails doc : http://guides.rubyonrails.org/active_record_querying.html#scopes
Upvotes: 0