跳到內容 跳到搜尋
方法
D
I
R
U

實例公開方法

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)
# 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

increment_counter(counter_name, id, by: 1, touch: nil)

透過直接 SQL 更新,增加數字欄位一。

此方法主要用於維護用來儲存總和值的 counter_cache 欄位。例如,DiscussionBoard 可能會快取 posts_countcomments_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)
# 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

reset_counters(id, *counters, touch: nil)

使用 SQL 計算查詢,將一個或多個 counter cache 重設為其正確值。在新增新的 counter cache 時,或 counter 已損毀或透過 SQL 直接修改時,這會很有用。

參數

  • id - 你想重設其 counter 的物件 id。

  • counters - 要重設的一個或多個關聯 counter。可以提供關聯名稱或 counter 名稱。

  • :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 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

update_counters(id, counters)

一個通用「counter 更新」實作,目的是主要用於 increment_counterdecrement_counter,但也可以單獨使用。其對具有特定 ID 的記錄只做一個直接 SQL 更新,並根據對應值的數值,調整給定的 counters hash 量。

參數

  • id - 你想更新其 counter 的物件 id 或陣列 id。

  • 計數器 - 包含要更新的欄位名稱(作為鍵)和要更新欄位的數量(作為值)的 雜湊

  • :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)
# 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