Module: EagerCounting::CountBy::ClassMethods

Defined in:
lib/eager_counting/count_by.rb

Instance Method Summary collapse

Instance Method Details

#count_by(association_target, scope = nil) ⇒ Object

Performs a count grouped by the given association. This means it will return a hash mapping the ids of the associated objects to the number of rows this class has for each of them.

Example:

class Comment < ActiveRecord::Base
  include EagerCounting::CountBy
  belongs_to :author
  belongs_to :commentable, polymorphic: true
end

Comment.count_by(:author) # => hash with author id mapped to number of comments this user made

You can call this method on any relation object of the class you included it on

Comment.where(spam: false).count_by(:author) # => will only count non spam comments

With the second argument you can also limit the scope of the association by which to count

Comment.count_by(:author, User.where(admin: false)) # => only count comments by non admin users

By passing an hash as the association you can count by joined associations

Comment.count_by(author: { city: :country }) # => count comments by the country their from

You can also use it on polymoprhic associations. For that the second parameter is necessary to select the type of things to count by.

Comment.count_by(:commentable, Picture.all) # => how many comments does each picture have?


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/eager_counting/count_by.rb', line 44

def count_by(association_target, scope = nil)
  association = deepest_value(association_target).to_s
  scope ||= association.camelize.constantize.all
  join = without_deepest_value(association_target)
  target_model = self

  if association_target.is_a? Hash
    target_model = deepest_value(join).to_s.singularize.camelize.constantize
  end

  query = joins(join)
    .merge(target_model.where(association => scope))
    .group(association_column_name(target_model, association))
    .count

  Hash.new(0).merge query
end