实例公共方法
decrement_counter(counter_name, id, by: 1, touch: nil) 链接
通过直接 SQL 更新,将数字字段减一。
这与 increment_counter 的工作方式相同,但将列值减少 1,而不是增加它。
参数¶ ↑
-
counter_name- 应减一的字段名称。 -
id- 应减一的对象 ID 或 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)
来源: 显示 | 在 GitHub 上
# 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
increment_counter(counter_name, id, by: 1, touch: nil) 链接
通过直接 SQL 更新,将数字字段加一。
此方法主要用于维护 counter_cache 列,这些列用于存储聚合值。例如,DiscussionBoard 可以缓存 posts_count 和 comments_count,以避免在每次显示时运行 SQL 查询来计算帖子和评论的数量。
参数¶ ↑
-
counter_name- 应增加的字段名称。 -
id- 应增加的对象 ID 或 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)
来源: 显示 | 在 GitHub 上
# 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
reset_counters(id, *counters, touch: nil) 链接
使用 SQL count 查询将一个或多个计数缓存重置为其正确值。这对于添加新的计数缓存,或者计数缓存已被损坏或直接通过 SQL 修改的情况非常有用。
参数¶ ↑
-
id- 您希望重置计数器的对象 ID 或 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)
来源: 显示 | 在 GitHub 上
# 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
update_counters(id, counters) 链接
一个通用的“计数器更新器”实现,主要供 increment_counter 和 decrement_counter 使用,但也可单独使用。它只需对给定 ID 的记录执行直接 SQL 更新,并按照相应值指定的数量修改给定的计数器哈希。
参数¶ ↑
-
id- 您希望更新计数器的对象 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)
来源: 显示 | 在 GitHub 上
# 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