Spec-Zone.ru › Ruby on Rails 8.1

module ActiveRecord::CounterCache::ClassMethods

Публичные методы экземпляра

decrement_counter (counter_name, id, by: 1, touch: nil) Показать исходный код
# File activerecord/lib/active_record/counter_cache.rb, line 203
def decrement_counter(counter_name, id, by: 1, touch: nil)
  update_counters(id, counter_name => -by, touch: touch)
end

Уменьшает числовое поле на единицу с помощью прямого SQL-запроса на обновление.

Работает так же, как increment_counter, но уменьшает значение столбца на 1, а не увеличивает его.

Параметры

  • counter_name — имя поля, значение которого нужно уменьшить.

  • id — идентификатор объекта, значение которого нужно уменьшить, или массив идентификаторов.

  • :by — величина, на которую нужно уменьшить значение. По умолчанию — 1.

  • :touch — обновлять временные метки при обновлении. Передайте true, чтобы обновить updated_at и/или updated_on. Передайте символ, чтобы обновить соответствующий столбец, или массив символов, чтобы обновить только указанные столбцы.

Примеры

# Decrement the posts_count column for the record with an id of 5
DiscussionBoard.decrement_counter(:posts_count, 5)

# Decrement the posts_count column for the record with an id of 5
by a specific amount.
DiscussionBoard.decrement_counter(:posts_count, 5, by: 3)

# Decrement the posts_count column for the record with an id of 5
# and update the updated_at value.
DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
increment_counter (counter_name, id, by: 1, touch: nil) Показать исходный код
# File activerecord/lib/active_record/counter_cache.rb, line 173
def increment_counter(counter_name, id, by: 1, touch: nil)
  update_counters(id, counter_name => by, touch: touch)
end

Увеличивает числовое поле на единицу с помощью прямого SQL-запроса на обновление.

Этот метод в основном используется для поддержки столбцов counter_cache, в которых хранятся агрегированные значения. Например, DiscussionBoard может кэшировать posts_count и comments_count, чтобы не выполнять SQL-запрос для подсчёта количества публикаций и комментариев при каждом отображении.

Параметры

  • counter_name — имя поля, значение которого нужно увеличить.

  • id — идентификатор объекта, значение которого нужно увеличить, или массив идентификаторов.

  • :by — величина, на которую нужно увеличить значение. По умолчанию — 1.

  • :touch — обновлять временные метки при обновлении. Передайте true, чтобы обновить updated_at и/или updated_on. Передайте символ, чтобы обновить соответствующий столбец, или массив символов, чтобы обновить только указанные столбцы.

Примеры

# Increment the posts_count column for the record with an id of 5
DiscussionBoard.increment_counter(:posts_count, 5)

# Increment the posts_count column for the record with an id of 5
# by a specific amount.
DiscussionBoard.increment_counter(:posts_count, 5, by: 3)

# Increment the posts_count column for the record with an id of 5
# and update the updated_at value.
DiscussionBoard.increment_counter(:posts_count, 5, touch: true)
reset_counters (id, *counters, touch: nil) Показать исходный код
# File activerecord/lib/active_record/counter_cache.rb, line 37
def reset_counters(id, *counters, touch: nil)
  ids = if composite_primary_key?
    if id.first.is_a?(Array)
      id
    else
      [id]
    end
  else
    Array(id)
  end

  updates = Hash.new { |h, k| h[k] = {} }

  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

    counter_association = counter_association.to_sym
    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

    counts =
      unscoped
        .joins(counter_association)
        .where(primary_key => ids)
        .group(primary_key)
        .count(:all)

    ids.each do |id|
      updates[id].merge!(counter_name => counts[id] || 0)
    end
  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.each_value do |record_updates|
      record_updates.merge!(touch_updates)
    end
  end

  updates.each do |id, record_updates|
    unscoped.where(primary_key => [id]).update_all(record_updates)
  end

  true
end

Сбрасывает один или несколько кэшей счётчиков до правильных значений с помощью SQL-запроса подсчёта. Это полезно при добавлении новых кэшей счётчиков, а также если счётчик повреждён или изменён напрямую с помощью SQL.

Параметры

  • id — идентификатор объекта, для которого нужно сбросить счётчик, или массив идентификаторов.

  • counters — один или несколько счётчиков ассоциаций для сброса. Можно указать имя ассоциации или имя счётчика.

  • :touch — обновлять временные метки при обновлении. Передайте true, чтобы обновить updated_at и/или updated_on. Передайте символ, чтобы обновить соответствующий столбец, или массив символов, чтобы обновить только указанные столбцы.

Примеры

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

# For posts with ids #1 and #2, reset the comments_count
Post.reset_counters([1, 2], :comments)

# Like above, but also touch the updated_at and/or updated_on
# attributes.
Post.reset_counters(1, :comments, touch: true)
update_counters (id, counters) Показать исходный код
# File activerecord/lib/active_record/counter_cache.rb, line 140
def update_counters(id, counters)
  id = [id] if composite_primary_key? && id.is_a?(Array) && !id[0].is_a?(Array)
  unscoped.where!(primary_key => id).update_counters(counters)
end

Универсальная реализация «обновления счётчиков», предназначенная в первую очередь для использования методами increment_counter и decrement_counter, но также полезная и сама по себе. Она просто выполняет прямой SQL-запрос на обновление записи с указанным идентификатором, изменяя переданный хэш счётчиков на величины, заданные соответствующими значениями:

Параметры

  • id — идентификатор объекта, для которого нужно обновить счётчик, или массив идентификаторов.

  • counters — Hash, содержащий имена обновляемых полей в качестве ключей и величины изменения этих полей в качестве значений.

  • :touch — параметр; обновлять временные метки при обновлении. Если переданы имена атрибутов, они обновляются вместе с атрибутами updated_at/on.

Примеры

# For the Post with id of 5, decrement the comments_count by 1, and
# increment the actions_count by 1
Post.update_counters 5, comments_count: -1, actions_count: 1
# Executes the following SQL:
# UPDATE posts
#    SET comments_count = COALESCE(comments_count, 0) - 1,
#        actions_count = COALESCE(actions_count, 0) + 1
#  WHERE id = 5

# For the Posts with id of 10 and 15, increment the comments_count by 1
Post.update_counters [10, 15], comments_count: 1
# Executes the following SQL:
# UPDATE posts
#    SET comments_count = COALESCE(comments_count, 0) + 1
#  WHERE id IN (10, 15)

# For the Posts with id of 10 and 15, increment the comments_count by 1
# and update the updated_at value for each counter.
Post.update_counters [10, 15], comments_count: 1, touch: true
# Executes the following SQL:
# UPDATE posts
#    SET comments_count = COALESCE(comments_count, 0) + 1,
#    `updated_at` = '2016-10-13T09:59:23-05:00'
#  WHERE id IN (10, 15)

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API