2010-07-17 43 views
10

我正在學習Rails,並陷入了一個小問題。我寫死了簡單的應用程序與任務列表,讓模型看起來類似的東西:Rails模型中的多個counter_cache

class List < ActiveRecord::Base 
    has_many :tasks 
    has_many :undone_tasks, :class_name => 'Task', 
          :foreign_key => 'task_id', 
          :conditions => 'done = false' 
    # ... some validations 
end 

List模型列tasks_counterundone_tasks_counter

class Task < ActiveRecord::Base 
    belongs_to :list, :counter_cache => true 
    # .. some validations 
end 

有了這樣的代碼有attr_readonly :tasks_counterList實例,但我想有未完成的任務計數器爲好。有沒有辦法讓Rails自動緩存多個計數器。

到目前爲止,我已經設法創建TasksObserver增量或減量Task#undone_tasks_counter,但也許有一個更簡單的方法。

+0

你最終弄明白了嗎? – 2011-11-21 14:20:48

回答

19

您是否使用自定義計數器緩存列試過它? 這裏的DOC: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

這表明,你可以通過列名的counter_cache選項,你可能能夠調用兩次例如

belongs_to :list, :counter_cache => true  # will setup tasks_count 
belongs_to :list, :counter_cache => :undone_tasks_count 

注:沒有實際測試過。

+2

這實際上工作。很長一段時間沒有使用SO帳戶,感謝這樣乾淨的解決方案! – 2012-01-20 18:41:23

+1

我只是試過這個,結果是第二次緩存增加了兩次,第一次沒有。我想在去年有所改變? – Steven 2012-11-07 18:09:58

+0

@Steven你說得對。根據Rails API,您現在可以指定列的名稱,從而爲您節省了額外的步驟。 – 2013-02-14 23:42:05

-1

我不知道任何「automagical」方法。觀察者似乎對此很好,但我個人更喜歡在模型中使用回調(before_save,after_save)。

0

ez方式。

1)第一計數器 - 會做自動

2)手動 「正確」

AnotherModelHere 

    belongs_to :user, counter_cache: :first_friends_count 


    after_create :provide_correct_create_counter_2 
    after_destroy :provide_correct_destroy_counter_2 

    def provide_correct_create_counter_2 
     User.increment_counter(:second_friends_count, another_user.id) 
    end 

    def provide_correct_destroy_counter_2 
     User.decrement_counter(:second_friends_count, another_user.id) 
    end 
-1

則很可能需要counter_culture寶石,因爲它可以處理自定義條件和計數器將更新計數器值不僅在創建和銷燬,但更新太:

class CreateContainers < ActiveRecord::Migration[5.0] 
    create_table :containers, comment: 'Our awesome containers' do |t| 
    t.integer :items_count,  default: 0, null: false, comment: 'Caching counter for total items' 
    t.integer :loaded_items_count, default: 0, null: false, comment: 'Caching counter for loaded items' 
    end 
end 

class Container < ApplicationRecord 
    has_many :items, inverse_of: :container 
    has_many :loaded_items, -> { where.not(loaded_at: nil) }, 
      class_name: 'Item', 
      counter_cache: :loaded_items_count 
      # Notice that you can specify custom counter cache column name 
      # in has_many definition and AR will use it! 
end 

class Item < ApplicationRecord 
    belongs_to :container, inverse_of: :items, counter_cache: true 
    counter_culture :container, column_name: proc { |model| model.loaded_at.present? ? 'loaded_items_count' : nil } 
    # But this column value will be handled by counter_culture gem 
end