instance method reset_counters

Ruby on Rails 7.1.6

Since v4.0.13

Available in: v4.0.13 v4.1.16 v4.2.9 v5.2.8.1 v6.0.6 v6.1.7.10 v7.0.10 v7.1.6 v7.2.3 v8.0.4 v8.1.2

Signature

reset_counters(id, *counters, touch: nil)

Resets one or more counter caches to their correct value using an SQL count query. This is useful when adding new counter caches, or if the counter has been corrupted or modified directly by SQL.

Parameters

  • id - The id of the object you wish to reset a counter on.

  • counters - One or more association counters to reset. Association name or counter name can be given.

  • :touch - Touch timestamp columns when updating. Pass true to touch updated_at and/or updated_on. Pass a symbol to touch that column or an array of symbols to touch just those ones.

Examples

# For the Post with id #1, reset the comments_count
Post.reset_counters(1, :comments)

# Like above, but also touch the +updated_at+ and/or +updated_on+
# attributes.
Post.reset_counters(1, :comments, touch: true)

Parameters

id req
counters rest
touch key = nil
Source
# File activerecord/lib/active_record/counter_cache.rb, line 33
      def reset_counters(id, *counters, touch: nil)
        object = find(id)

        updates = {}
        counters.each do |counter_association|
          has_many_association = _reflect_on_association(counter_association)
          unless has_many_association
            has_many = reflect_on_all_associations(:has_many)
            has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym }
            counter_association = has_many_association.plural_name if has_many_association
          end
          raise ArgumentError, "'#{name}' has no association called '#{counter_association}'" unless has_many_association

          if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
            has_many_association = has_many_association.through_reflection
          end

          foreign_key  = has_many_association.foreign_key.to_s
          child_class  = has_many_association.klass
          reflection   = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
          counter_name = reflection.counter_cache_column

          count_was = object.send(counter_name)
          count = object.send(counter_association).count(:all)
          updates[counter_name] = count if count != count_was
        end

        if touch
          names = touch if touch != true
          names = Array.wrap(names)
          options = names.extract_options!
          touch_updates = touch_attributes_with_time(*names, **options)
          updates.merge!(touch_updates)
        end

        unscoped.where(primary_key => [object.id]).update_all(updates) if updates.any?

        true
      end

Defined in activerecord/lib/active_record/counter_cache.rb line 33 · View on GitHub · Improve this page · Find usages on GitHub

Defined in ActiveRecord::CounterCache::ClassMethods

Type at least 2 characters to search.

↑↓ navigate · open · esc close