Rails counter_cache problem

Posted by Curtis Miller Curtis Miller

I ran into a strange Ruby on Rails counter_cache problem today. Given the following example models:

class Poll < ActiveRecord::Base
  has_many :poll_choices
  has_many :poll_votes
end

class PollChoice < ActiveRecord::Base
  belongs_to :poll
  has_many :poll_votes
end

class PollVote < ActiveRecord::Base
  belongs_to :poll, :counter_cache => :votes_count
  belongs_to :poll_choice, :counter_cache => :votes_count
end

We want to ensure that the Poll maintains the total vote count. We also want the PollChoice to maintain the votes for that specific choice. In our controller we might be tempted to add a PollVote through either the Poll or PollChoice association with PollVote, but that's where the problem appears.

It turns out that both of the following approaches will only update the votes_count for one or the other instance, but not both.

@poll.poll_votes.create(:poll_choice_id => @poll_choice.id)

OR

@poll_choice.poll_votes.create(:poll_id => @poll.id)

Instead, if we create the PollVote directly we will get the desired result of both the Poll and PollChoice having their votes_count updated appropriately.

PollVote.create(:poll_id => @poll.id, :poll_choice_id => @poll_choice.id)

Strange behavior or expected result?

Update: Another solution is to not assign using the ID, but instead assign using the object itself.

@poll.poll_votes.create(:poll_choice => @poll_choice)

OR

@poll_choice.poll_votes.create(:poll => @poll)

A quick test showed this worked as well. (Thanks Arya A)



Velocity Labs

Need web application development, maintenance for your existing app, or a third party code review?

Velocity Labs can help.

Hire us!