Automatic counter_cache maintenance.
Written on December 7, 2007 by Chris Heald
I upgraded to Rails 2.0 today, and found that countercache columns were suddenly :readonly, which means that you can’t update them with your regular old model.associationcount = model.association.count routine. So, I whipped up the following ActiveRecord patch.
module TagTeamInteractive
module ActiveRecordSynchCounters
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def synch_all_counters!
self.find(:all).each do |u|
u.synch_counters!
end
end
end
module InstanceMethods
def synch_counters!
fields = {}
self.attributes.each do |k, v|
if k.match /_count$/ then
begin
f = k.gsub(/_count$/, "")
assoc = self.class.reflect_on_association(f.to_sym)
if assoc.macro == :has_many then
fields[f.to_sym] = self.send(f.to_sym).count - v
else
next
end
rescue
next
end
end
end
self.class.update_counters(id, fields) unless fields.empty?
end
end
end
end
ActiveRecord::Base.send(:include, TagTeamInteractive::ActiveRecordSynchCounters)
ActiveRecord::Base.send(:include, TagTeamInteractive::ActiveRecordSynchCounters::InstanceMethods)
Easy enough. Load that in your environment.rb, and then you can use the following:
Dir.glob("#{RAILSROOT}/app/models/*.rb”).each do |file|
m = File.basename(file).split(”.”).first.camelize.constantize
synchallcounters! if m.isa? ActiveRecord::Base
end
That’ll run synchallcounters! for each record on each model in your database. Instant counter re-synching across the entire database. Tada!
Posted in
