модуль ActiveRecord::CounterCache::ClassMethods
Открытые методы экземпляров
# File activerecord/lib/active_record/counter_cache.rb, line 178 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)
# File activerecord/lib/active_record/counter_cache.rb, line 148 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)
# File activerecord/lib/active_record/counter_cache.rb, line 34
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 Сбрасывает один или несколько счетчиков кэша до правильного значения, используя запрос 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) # Like above, but also touch the +updated_at+ and/or +updated_on+ # attributes. Post.reset_counters(1, :comments, touch: true)
# File activerecord/lib/active_record/counter_cache.rb, line 115 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, изменяя заданный хеш счетчиков на соответствующую величину:
Параметры
-
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.