module Mongoid::Relations::CounterCache::ClassMethods

Public Instance Methods

decrement_counter(counter_name, id) click to toggle source

Decrement the counter name from the entries that match the id by one. This method is used on associations callbacks when counter_cache is enabled

@example Decrement comments counter

Post.decrement_counter(:comments_count, '50e0edd97c71c17ea9000001')

@param [ Symbol ] Counter cache name @param [ String ] The id of the object that will have its counter decremented.

@since 3.1.0

# File lib/mongoid/relations/counter_cache.rb, line 87
def decrement_counter(counter_name, id)
  update_counters(id, counter_name.to_sym => -1)
end
increment_counter(counter_name, id) click to toggle source

Increment the counter name from the entries that match the id by one. This method is used on associations callbacks when counter_cache is enabled

@example Increment comments counter

Post.increment_counter(:comments_count, '50e0edd97c71c17ea9000001')

@param [ Symbol ] Counter cache name @param [ String ] The id of the object that will have its counter incremented.

@since 3.1.0

# File lib/mongoid/relations/counter_cache.rb, line 72
def increment_counter(counter_name, id)
  update_counters(id, counter_name.to_sym => 1)
end
reset_counters(id, *counters) click to toggle source

Reset the given counter using the .count() query from the db. This method is usuful in case that a counter got corrupted, or a new counter was added to the collection.

@example Reset the given counter cache

Post.reset_counters('50e0edd97c71c17ea9000001', :comments)

@param [ String ] The id of the object that will be reset. @param [ Symbol, Array ] One or more counter caches to reset

@since 3.1.0

# File lib/mongoid/relations/counter_cache.rb, line 35
def reset_counters(id, *counters)
  document = id.is_a?(Document) ? id : find(id)
  counters.each do |name|
    meta = reflect_on_association(name)
    inverse = meta.klass.reflect_on_association(meta.inverse)
    counter_name = inverse.counter_cache_column_name
    document.update_attribute(counter_name, document.send(name).count)
  end
end
update_counters(id, counters) click to toggle source

Update the given counters by the value factor. It uses the atomic $inc command.

@example Add 5 to comments counter and remove 2 from likes

counter.
Post.update_counters('50e0edd97c71c17ea9000001',
           :comments_count => 5, :likes_count => -2)

@param [ String ] The id of the object to update. @param [ Hash ] Key = counter_cache and Value = factor.

@since 3.1.0

# File lib/mongoid/relations/counter_cache.rb, line 57
def update_counters(id, counters)
  where(:_id => id).inc(counters)
end

Private Instance Methods

add_counter_cache_callbacks(meta) click to toggle source

Add the callbacks responsible for update the counter cache field

@api private

@example Add the touchable.

Person.add_counter_cache_callbacks(meta)

@param [ Metadata ] metadata The metadata for the relation.

@since 3.1.0

# File lib/mongoid/relations/counter_cache.rb, line 103
def add_counter_cache_callbacks(meta)
  name = meta.name
  cache_column = meta.counter_cache_column_name.to_sym

  after_update do
    if record = __send__(name)
      foreign_key = meta.foreign_key

      if attribute_changed?(foreign_key)
        original, current = attribute_change(foreign_key)

        unless original.nil?
          record.class.with(persistence_context) do |_class|
            _class.decrement_counter(cache_column, original)
          end
        end

        unless current.nil?
          record[cache_column] = (record[cache_column] || 0) + 1
          record.class.with(record.persistence_context) do |_class|
            _class.increment_counter(cache_column, current) if record.persisted?
          end
        end
      end
    end
  end

  after_create do
    if record = __send__(name)
      record[cache_column] = (record[cache_column] || 0) + 1

      if record.persisted?
        record.class.with(record.persistence_context) do |_class|
          _class.increment_counter(cache_column, record._id)
        end
        record.remove_change(cache_column)
      end
    end
  end

  before_destroy do
    if record = __send__(name)
      record[cache_column] = (record[cache_column] || 0) - 1 unless record.frozen?

      if record.persisted?
        record.class.with(record.persistence_context) do |_class|
          _class.decrement_counter(cache_column, record._id)
        end
        record.remove_change(cache_column)
      end
    end
  end
end