Gần đây tôi đi qua cùng một vấn đề này (Rails 3.2.3). Có vẻ như nó chưa được sửa, nên tôi phải tiếp tục và sửa chữa. Dưới đây là cách tôi đã sửa đổi ActiveRecord :: Base và sử dụng gọi lại after_update để giữ cho counter_caches của tôi được đồng bộ.
Mở rộng ActiveRecord :: Base
Tạo một file mới lib/fix_counters_update.rb
như sau:
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)
Đoạn mã trên sử dụng phương pháp ActiveModel::Dirtychanges
mà trả về một băm chứa các thuộc tính thay đổi và một mảng của cả giá trị cũ và giá trị mới. Bằng cách kiểm tra thuộc tính để xem liệu đó có phải là mối quan hệ (tức là kết thúc bằng/_id /) hay không, bạn có thể xác định có điều kiện xem decrement_counter
và/hoặc increment_counter
có cần chạy hay không. Đó là essnetial để kiểm tra sự hiện diện của nil
trong mảng, nếu không sẽ xảy ra lỗi.
Thêm vào Initializers
Tạo một file mới config/initializers/active_record_extensions.rb
như sau:
require 'fix_update_counters'
Thêm vào mô hình
Đối với mỗi mô hình mà bạn muốn lưu trữ truy cập được cập nhật thêm gọi lại:
class Comment < ActiveRecord::Base
after_update :fix_updated_counters
....
end
Điều đó có thể sẽ ném ra một lỗi nếu container_id/container_id_was là con số không. – Zequez