problem writing to a counter_cache with update_attribute

I’m sure you read Frederick’s response about the counter_cache being readonly.

The way to properly populate these during a migration is to redeclare the Learner class as an inner-class of the Migration itself, specifying only minimal functionality.

class AddCounterCacheToLearners < ActiveRecord::Migration

class Learner < ActiveRecord::Base

def reset_column_information

  # re-implement reset_column_information functionality here

end

end

def self.up add_column :learners, :learner_sessions_count, :integer, :default => 0 Learner.reset_column_information end

def self.down remove_column :learners, :learner_sessions_count

end end

Thanks Frederic and Duncan,

FYI: here's the complete migration for the simple test case that adds a counter_cache AND sets the value.

class AddCounterCacheToLearners < ActiveRecord::Migration    class Learner < ActiveRecord::Base      has_many :learner_sessions      def reset_column_information        # re-implement reset_column_information functionality here        generated_methods.each { |name| undef_method(name) }        @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @generated_methods = @inheritance_column = nil      end    end

   def self.up      add_column :learners, :learner_sessions_count, :integer, :default => 0      Learner.reset_column_information      Learner.find(:all).each do |learner|        count = learner.learner_sessions.count        learner.update_attribute(:learner_sessions_count, count)      end    end

   def self.down      remove_column :learners, :learner_sessions_count    end end

Or you could use #228 Add add_counter_cache_column to ActiveRecord migrations - Ruby on Rails - rails :slight_smile:

Thanks for that pointer Damian. I didnm't know about the class method Model.update_counters.

I've simplified my migration as follows:

class AddCounterCacheToLearners < ActiveRecord::Migration   def self.up     add_column :learners, :learner_sessions_count, :integer, :default => 0     Learner.reset_column_information     Learner.find(:all).each do |learner|       change_in_count = learner.learner_sessions.count - learner.learner_sessions_count       Learner.update_counters(learner.id, :learner_sessions_count => change_in_count)     end   end

  def self.down     remove_column :learners, :learner_sessions_count   end end

While this is better than my previous solution it still seems a bit ugly.

I like your proposed patch but it's marked as "wontfix".

In my simplified migration above this section:

    Learner.reset_column_information     Learner.find(:all).each do |learner|       change_in_count = learner.learner_sessions.count - learner.learner_sessions_count       Learner.update_counters(learner.id, :learner_sessions_count => change_in_count)     end

is equivalent to the suggestions at the end of your patch discussion for a class method something like this:

    Learner.update_counter_cache

I like some of the ideas here, and I've been annoyed by this issue quite a few times. Did a new ticket get created, or was a consensus about an approach reached?

- Trevor

No consensus :-/

I think the resolution was "we don't want yet another migration helper" (?).

I like the idea of adding a class method like Model.reset_counter_cache(:column_name)

I don't think there is a new ticket.

I like that as well. I made a new ticket:

http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1211-reset_counter_cache

This is probably something I can work on, unless somebody else is chomping at the bit.