Недавно я столкнулся с этой же проблемой (Rails 3.2.3). Похоже, что это еще не исправлено, поэтому я должен был пойти дальше и исправить. Ниже показано, как я изменил ActiveRecord :: Base и использую обратный вызов after_update для синхронизации моих counter_caches.
Расширение ActiveRecord :: Base
Создайте новый файл lib/fix_counters_update.rb
со следующим:
module FixUpdateCounters
def fix_updated_counters
self.changes.each {|key, value|
# key should match /master_files_id/ or /bibls_id/
# value should be an array ['old value', 'new value']
if key =~ /_id/
changed_class = key.sub(/_id/, '')
changed_class.camelcase.constantize.decrement_counter(:"#{self.class.name.underscore.pluralize}_count", value[0]) unless value[0] == nil
changed_class.camelcase.constantize.increment_counter(:"#{self.class.name.underscore.pluralize}_count", value[1]) unless value[1] == nil
end
}
end
end
ActiveRecord::Base.send(:include, FixUpdateCounters)
В приведенном выше коде используется метод ActiveModel :: Dirty changes
, который возвращает хеш, содержащий измененный атрибут и массив как старого, так и нового значения. Протестировав атрибут, чтобы определить, является ли это отношением (т.е. оканчивается на / _id /), вы можете условно определить, нужно ли запускать decrement_counter
и / или increment_counter
. Необходимо проверить наличие nil
в массиве, в противном случае возникнут ошибки.
Добавить к инициализаторам
Создайте новый файл config/initializers/active_record_extensions.rb
со следующим:
require 'fix_update_counters'
Добавить к моделям
Для каждой модели, которую вы хотите обновить кэши счетчиков, добавьте обратный вызов:
class Comment < ActiveRecord::Base
after_update :fix_updated_counters
....
end