# Counter Problem

**URL:** <https://www.ruby-forum.com/t/counter-problem/104139>\
**Category:** Rails\
**Created:** [May 14, 2007, 6:08pm UTC](https://www.ruby-forum.com/t/counter-problem/104139 "2007-05-14T18:08:36Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [May 14, 2007, 6:08pm UTC](https://www.ruby-forum.com/t/counter-problem/104139/1 "2007-05-14T18:08:36Z")

</div>

Hi. I have a problem with counters in Rails. The situation looks like  
this:  
-3 simple models

class Forum \< ActiveRecord::Base  
has\_many :posts  
end  
class Topic \< ActiveRecord::Base  
has\_many :posts  
end  
class Post \< ActiveRecord::Base  
belongs\_to :topic, :counter\_cache =\> true  
belongs\_to :forum, :counter\_cache =\> true  
end

- In migrations i have declared  
t.column :posts\_count, :integer, :default =\> 0  
for Forum and Topic

- Now a simple action

def some\_action  
@post = Post.new(params[:id])

@forum.posts \<\< @post # The @forums.posts\_count is up by 1  
@topic.posts \<\< @post # The @topic.posts\_count is _not_ up by 1  
end

Both, the forum\_id and topic\_id are set correctly in @post, it saves  
into the database and everything else is dandy. But why oh why doesn’t  
the @topic.posts\_count increment ? (oh, obviously if I change the order  
of the two crucial lines the effect will be the same - the instance in  
the second line won’t get the posts\_count incremented)

Could anyone come up with a solution ? (apart from making the counters  
‘by hand’)

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [May 14, 2007, 9:06pm UTC](https://www.ruby-forum.com/t/counter-problem/104139/2 "2007-05-14T21:06:32Z")

</div>

> @forum.posts \<\< @post # The @forums.posts\_count is up by 1  
> @topic.posts \<\< @post # The @topic.posts\_count is _not_ up by 1

Just a guess, but I think it only updates on the first attempt because  
increment\_counter is only called if the it’s a new record.

So, for the first one, it’s a new record, but for the second it’s  
existing - so no update.

Do the counters update correctly on save?

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [May 14, 2007, 9:15pm UTC](https://www.ruby-forum.com/t/counter-problem/104139/3 "2007-05-14T21:15:51Z")

</div>

The fundamental problem is that in order to increment the counter when  
an existing record was associated, an extra query would be required to  
determine whether that record was already included in the count. At  
that point the performance gain of the counter is lost since you might  
as well just query for the COUNT again. Then there’s the whole issue  
of deleting posts. I’m assuming the counter would not decrement  
unless you call @forum.posts.delete(id).

In my experience the counter caches are scarily brittle. If the given  
model is ONLY created through the association then they can be  
manageable and offer a slight performance benefit, but if you have the  
proper index, a COUNT(\*) query is extremely fast.

On May 14, 1:06 pm, David C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![asetzler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ac91a4/32.png) [@asetzler](https://www.ruby-forum.com/u/asetzler)\
**Post date:** [May 15, 2007, 12:44am UTC](https://www.ruby-forum.com/t/counter-problem/104139/4 "2007-05-15T00:44:30Z")

</div>

> > Do the counters update correctly on save?

Very much inline with what dasil said, the rails counters are very  
brittle, but they are typically per-object caches, so this should be  
alright. However, to be sure, I recommend in a unit test, trying out.

assert\_equal @forum.posts.count, 1  
assert\_equal @topic.posts.count, 1

Your assertion may very well fail, but you should check log/test.log  
and examine what SQL queries Rails dispatched if any.
