Spec-Zone.ru › Ruby on Rails 5.2

модуль ActiveRecord::CounterCache::ClassMethods

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

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

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

Этот метод работает так же, как increment_counter, но уменьшает значение столбца на 1 вместо увеличения.

Параметры

  • counter_name - Имя поля, которое должно быть уменьшено.

  • id - ID объекта, который нужно уменьшить, или массив ID.

  • :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
# and update the updated_at value.
DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
increment_counter(counter_name, id, touch: nil) Показать исходный код
# File activerecord/lib/active_record/counter_cache.rb, line 151
def increment_counter(counter_name, id, touch: nil)
  update_counters(id, counter_name => 1, touch: touch)
end

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

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

Параметры

  • counter_name - Имя поля, которое должно быть увеличено.

  • id - ID объекта, который нужно увеличить, или массив ID.

  • :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
# 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 29
def reset_counters(id, *counters, touch: nil)
  object = find(id)

  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

    updates = { counter_name => object.send(counter_association).count(:all) }

    if touch
      names = touch if touch != true
      updates.merge!(touch_attributes_with_time(*names))
    end

    unscoped.where(primary_key => object.id).update_all(updates)
  end

  true
end

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

Параметры

  • id - ID объекта, счётчик которого вы хотите сбросить.

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

  • :touch - Обновить метки временных столбцов при обновлении. Передайте true для обновления updated_at и/или updated_on. Передайте символ для обновления этого столбца или массив символов для обновления только этих столбцов.

Примеры

# 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)
update_counters(id, counters) Показать исходный код
# File activerecord/lib/active_record/counter_cache.rb, line 104
def update_counters(id, counters)
  touch = counters.delete(:touch)

  updates = counters.map do |counter_name, value|
    operator = value < 0 ? "-" : "+"
    quoted_column = connection.quote_column_name(counter_name)
    "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
  end

  if touch
    names = touch if touch != true
    touch_updates = touch_attributes_with_time(*names)
    updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
  end

  if id.is_a?(Relation) && self == id.klass
    relation = id
  else
    relation = unscoped.where!(primary_key => id)
  end

  relation.update_all updates.join(", ")
end

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

Параметры

  • id - ID объекта, счётчик которого вы хотите обновить, или массив ID.

  • counters - Хэш, содержащий имена полей для обновления в качестве ключей и величину изменения поля в качестве значений.

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

Примеры

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

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

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

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

Spec-Zone.ru

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