Selections, updates and counter caches

Hi All,

Just wondered how you are meant to get around this little issue:

I have a Company model, which has_many :people and I keep track of the
number with a counter cache:

class Company < ActiveRecord::Base
has_many :people
end

class Person < ActiveRecord::Base
belongs_to :company, :counter_cache => true
end

Creating new records, deleting them and reassigning people to new
companies all works fine.

However, I have a form to edit people which includes a selection list to
pick the company:
(in /people/edit.html.erb)
<%= collection_select(:person, :company_id, @companies, :id, :name,
{:prompt => true}) %>

Now here’s the killer - Since the controller updates the attributes the
company_id is changed but the counter cache is NOT:

  if @person.update_attributes(params[:person])
    flash[:notice] = 'Person was successfully updated.'
    format.html { redirect_to(people_path) }
    format.xml  { head :ok }
  else

Of course, changing the company through the association works perfectly,
so the work around is to do something like the following:

  @person.company = Company.find params[:person][:company_id]
  if @person.update_attributes(params[:person])
    flash[:notice] = 'Person was successfully updated.'

For extra security and peace of mind, it should also pay to make the
company_id field in the People model protected (rather than readonly,
which would allow the instance to be out of step with the database):

class Person < ActiveRecord::Base
belongs_to :company, :counter_cache => true
attr_protected :company_id
end

I would submit a patch to do this automatically for all counter caches,
but it is beyond my abilities at the moment.