Should I create a bug report?
I created a simple test app in 2.2.1 to isolate the problem.
# create the learner and learner_session models and migrations:
script/generate model learner name:string learner_session_id:integer
script/generate model learner_session learner_id:integer
rake db:migrate
# add the associations to the models:
class Learner < ActiveRecord::Base
has_many :learner_sessions
end
class LearnerSession < ActiveRecord::Base
belongs_to :learner
end
# create a learner and 2 learner sessions without a counter_cache
$ script/console
>> l = Learner.create(:name => "stephen")
=> #<Learner id: 1, name: "stephen", learner_session_id: nil>
>> l.learner_sessions.create
=> #<LearnerSession id: 1, learner_id: 1>
>> l.learner_sessions.create
=> #<LearnerSession id: 2, learner_id: 1>
>> l.learner_sessions.count
=> 2
# now run this migration:
class AddCounterCacheToLearners < ActiveRecord::Migration
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
# and add the counter_cache to the belongs_to association
class LearnerSession < ActiveRecord::Base
belongs_to :learner, :counter_cache => true
end
# back into script/console
$ script/console
>> l = Learner.find(:first)
=> #<Learner id: 1, name: "stephen", learner_session_id: nil,
learner_sessions_count: 0>
# there are still 2 learner sessions:
>> l.learner_sessions.count
=> 2
# but the learner_sessions_count is not set yet:
>> l.learner_sessions_count
=> 0
# update the learner_sessions_count:
>> l.update_attribute(:learner_sessions_count, 2)
=> true
# it is written to the model object:
>> l
=> #<Learner id: 1, name: "stephen", learner_session_id: nil,
learner_sessions_count: 2>
>> l.learner_sessions_count
=> 2
# but not to the database
>> l = Learner.find(:first)
=> #<Learner id: 1, name: "stephen", learner_session_id: nil,
learner_sessions_count: 0>
>
> I added a counter_cache to an existing parent-child model pair and
> wanted to set all the values for the counter_cache but can't do it
> using update_attribute (or a number of other methods).
>
> Should I create a bug report?
>
From the docs (http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html
):
> Note: Specifying a counter cache will add it to that model‘s list of
> readonly attributes using attr_readonly.
Fred
>
I added a counter_cache to an existing parent-child model pair and
wanted to set all the values for the counter_cache but can't do it
using update_attribute (or a number of other methods).
Should I create a bug report?
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
Or you could use http://rails.lighthouseapp.com/projects/8994/tickets/228 :-)
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
No consensus :-/
I think the resolution was "we don't want yet another migration helper" (?).
I don't think there is a new ticket.
--
Cheers!
- Pratik
http://m.onkey.org