module EagerCounting::CountBy::ClassMethods
Public Instance Methods
count_by(association_target, scope = nil)
click to toggle source
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?
# 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
Private Instance Methods
association_column_name(klass, association)
click to toggle source
# File lib/eager_counting/count_by.rb, line 64 def association_column_name(klass, association) "#{klass.table_name}.#{klass.reflections[association].foreign_key}" end
deepest_value(value)
click to toggle source
# File lib/eager_counting/count_by.rb, line 78 def deepest_value(value) if value.is_a? Hash deepest_value(value.values.first) else value end end
without_deepest_value(map)
click to toggle source
# File lib/eager_counting/count_by.rb, line 68 def without_deepest_value(map) return {} unless map.is_a? Hash key, value = map.to_a.first if value.is_a? Hash { key => without_deepest_value(value) } else key end end