Множественный counter_cache в модели Rails - PullRequest
10 голосов
/ 17 июля 2010

Я изучаю 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, но, возможно, есть более простой способ.

Ответы [ 4 ]

22 голосов
/ 03 ноября 2011

Вы пробовали это с колонкой пользовательского счетчика-кеша?Документ здесь: 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

Примечание: нефактически проверено.

0 голосов
/ 03 апреля 2017

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

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
0 голосов
/ 17 июля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...