Reputation: 843
There are Articles and Comments.
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :article, counter_cache: true
end
You can count number of comment by doing something like this: @article.comments_count
The question is - how would you count the number of unique users who left a comment on a specific @article ? (note: a unique user can leave multiple comments)
here's a scenario:
- comment - user_id(1)
- comment - user_id(4)
- comment - user_id(1)
comments count = 3
commenters (unique user who left a comment) count = 2
Upvotes: 0
Views: 319
Reputation: 5055
Rails has the wonderful distinct
query method which makes this particular query easy to generate:
Comment.where(article_id: article.id).select(:user_id).distinct.count
which generates the following SQL:
SELECT DISTINCT COUNT(DISTINCT "comments"."user_id") FROM "comments" WHERE "comments"."article_id" = ?
The benefit of this approach is you allow the database to do the heavy lifting. The database will often be several orders of magnitude faster than manipulating the objects directly in Ruby.
If you're willing to modify your Article
class as follows:
class Article < ActiveRecord::Base
has_many :comments
has_many :commenters, through: :comments, source: :user
has_many :unique_commenters, -> { distinct }, through: :comments, source: :user
end
you can also use the following code to generate a query:
article.unique_commenters
which generates the following SQL:
SELECT DISTINCT "users".* FROM "users" INNER JOIN "comments" ON "users"."id" = "comments"."user_id" WHERE "comments"."article_id" = ?
Upvotes: 3
Reputation: 4802
The best way I know is create a scope:
class Comment
belongs_to :user
belongs_to :article, counter_cache: true
scope :count_by_user ->(user) { where(user_id: user.id).count }
end
Then:
@article.comments.count_by_user(user) # 2
Upvotes: -1
Reputation: 1131
@article.comments.uniq.pluck(:user_id)
or just pluck
@article.comments.pluck("DISTINCT user_id")
Upvotes: 1
Reputation: 8062
you could use Ruby's Set
for this:
unique_commenters = Set.new
comments.each do |comment|
unique_commenters.add comment.user
end
unique_commenters.to_a
You could also just do commenters.uniq!
on the collection, but I guess that is less efficient.
Upvotes: -1