Несколько экземпляров counter_cache в модели 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_counter и undone_tasks_counter.

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

С таким кодом есть экземпляры attr_readonly :tasks_counter для List, но я также хотел бы иметь счетчик для отмененных задач. Есть ли способ автоматического резервного копирования нескольких счетчиков с помощью Rails.

До сих пор мне удалось создать TasksObserver, который увеличивает или уменьшает Task#undone_tasks_counter, но, возможно, есть более простой способ.

Ответ 1

Вы пробовали его с помощью столбца custom-counter-cache? Док здесь: 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

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

Ответ 3

Я не знаю ни одного "автоматизированного" метода для этого. Наблюдатели кажутся хорошими для этого, но я лично предпочитаю использовать обратные вызовы в модели (before_save, after_save).

Ответ 4

Скорее всего, вам понадобится 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