complete_morons
complete_morons

Reputation: 843

Count number of commenters

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:

  1. comment - user_id(1)
  2. comment - user_id(4)
  3. comment - user_id(1)

comments count = 3
commenters (unique user who left a comment) count = 2

Upvotes: 0

Views: 319

Answers (5)

locriani
locriani

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

Rodrigo
Rodrigo

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

usha
usha

Reputation: 29349

article.comments.collect(&:user).uniq{|user| user.id}.count

Upvotes: 0

Michael Liu
Michael Liu

Reputation: 1131

Try using pluck and uniq

@article.comments.uniq.pluck(:user_id)

or just pluck

@article.comments.pluck("DISTINCT user_id")

Upvotes: 1

rodrigoalvesvieira
rodrigoalvesvieira

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

Related Questions