2010-07-17 44 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