Correct use of counter caches?

I have trouble using :counter_cache => true on some of my belongs_to
associations.

When have say, Person which belongs_to :company, :counter_cache => true
and I update a Person’s record assigning that person to a different
company, it appears that the counter is not updated.

Ideally, person.update_attributes(params[:person]) should handle this
magically if a new :company_id is in the params. I have several
situations where I need to change the belongs_to association on a model
instance based on form input. Are counter_caches useful here? Is there
a trick to it?

It seems that only company.people << person works.

Am I missing something?

Best,

Steven

Counter_cache is completly broken as of now:

http://dev.rubyonrails.org/ticket/5050

You shouldn’t use ANY counters in counters in a class that you use
AR#save on. The patch at the bottom of the ticker does resolve this,
but it has to be done directly in the active record code.

To clarify what the problem is:
The counter_cache isn’t thread safe. You can never use ‘update


set my_count = #’ when dealing with counters, unless you lock the row
before you do your select, to prevent other updates from being lost.

You should only ever do ‘update table set my_count = my_count + #’.
Unfortunately AR doesn’t handle this currently.

Slain W. wrote:

To clarify what the problem is:
The counter_cache isn’t thread safe. You can never use ‘update


set my_count = #’ when dealing with counters, unless you lock the row
before you do your select, to prevent other updates from being lost.

You should only ever do ‘update table set my_count = my_count + #’.
Unfortunately AR doesn’t handle this currently.

Okay, I think I understand the severity of this but I am unsure how this
relates to my issue.

Basically, if I am updating a belongs_to associated object and I am
updating the value of the foreign key for the association, no attempt is
made by rails to modify the counter_cache.

I only use the caches in a non-critical area of the admin section of my
site. It is enough to update them periodically. The only thing I have
noticed this does affect is pagination.

If the counter cache is a lower value than the actual number of
associated records, pagination will only give me as many pages as the
cache value would indicate.

I will steer clear of dependency on counter caches but they are
necessary to cut down queries to the db on result list pages. Perhaps
with a little indexing, even that won’t be a problem.

Steven

Basically, if I am updating a belongs_to associated object and I am
updating the value of the foreign key for the association, no attempt is
made by rails to modify the counter_cache.

AR#save by default saves all fields. I can’t remember exactly what
happens since I don’t use counter_cache anymore. Have you checked the
log to see if it actually is getting updated but that the update is lost
when you save the save the parent record? This was how I first noticed
the problem. Also, I’m not sure if the counter_cache code triggers
unless you do it thru the parent.

Ie. if you have class Forum which has many Class Article, and you have
an article_count in your Forum class, you may need to do
forum_instance.articles << Article.new to get that to trigger. Just
cant remember.

I only use the caches in a non-critical area of the admin section of my
site. It is enough to update them periodically. The only thing I have
noticed this does affect is pagination.

If the counter cache is a lower value than the actual number of
associated records, pagination will only give me as many pages as the
cache value would indicate.

I will steer clear of dependency on counter caches but they are
necessary to cut down queries to the db on result list pages. Perhaps
with a little indexing, even that won’t be a problem.

Or you can patch AR to not include *_count fields when doing AR#save,
and use AR#increment_counter for the *_count fields.