Rails模型中的多个counter_cache

时间:2010-07-17 11:22:31

标签: ruby-on-rails

我正在学习Rails,并遇到了一个小问题。我正在用任务列表编写死的简单应用程序,因此模型看起来像这样:

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,但也许有一种更简单的方法。

4 个答案:

答案 0 :(得分:22)

您是否尝试使用自定义计数器缓存列? 这里的文件: 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

注意:未进行实际测试。

答案 1 :(得分:0)

是的,方式。

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

答案 2 :(得分:-1)

很可能你需要counter_culture gem,因为它可以处理具有自定义条件的计数器,并且不仅会在创建和销毁时更新计数器值,还会更新更新:

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

答案 3 :(得分:-2)

我不知道任何“自动”方法。观察者似乎对此很好,但我个人更喜欢在模型中使用回调(before_saveafter_save)。