5

I get the error Unknown key(s): counter_cache when trying to implement a counter cache column in my RoR app.

I implemented the model associations in this question: Model association question

Here's my migration:

class AddVideoVotesCountToVideos < ActiveRecord::Migration
  def self.up
    add_column :videos, :video_votes_count, :integer, :default => 0

    Video.reset_column_information
    Video.find(:all).each do |p|
      p.update_attributes :videos_votes_count, p.video_votes.length
    end
  end

  def self.down
    remove_column :videos, :video_votes_count
  end
end

However, after watching http://media.railscasts.com/videos/023_counter_cache_column.mov I thought that maybe I had to move :counter_cache => true into the VideoVote model after belongs_to :video. However, when I do that, I get the error:

wrong number of arguments (2 for 1)

What am I doing wrong?

Community
  • 1
  • 1
Justin Meltzer
  • 13,318
  • 32
  • 117
  • 182

4 Answers4

4

update_attribute not update_attribteS

p.update_attribute :videos_votes_count, p.video_votes.length

or with update_attributes:

p.update_attributes( :video_votes_count => p.video_votes.length )

UPD 1

:counter_cache => true should be at the VideoVote class:

class VideoVote < ActiveRecord::Base
  belongs_to :user
  belongs_to :video, :counter_cache => true
end
fl00r
  • 82,987
  • 33
  • 217
  • 237
  • still get the first error... where should `:counter_cache => true` go? – Justin Meltzer Mar 17 '11 at 19:28
  • ok, now I get this error: `undefined method 'videos_votes_count=' for #` – Justin Meltzer Mar 17 '11 at 19:37
  • you use `update_attributes` or `update_attribute`? Also you can temprory remove `counter_cache => true` because it obviously locks field – fl00r Mar 17 '11 at 19:40
  • What method do you use, which one `update_attributes` or `update_attribute` ? :) and remove `counter_cache => true` for a while, do your migrate and return it back :) – fl00r Mar 17 '11 at 19:42
  • ahh ok yeah, that solved it, I needed to take out counter_cache, migrate, and then return it back... thanks! – Justin Meltzer Mar 17 '11 at 19:45
3

To do counter_caching,you need to run the migration first that fills in the count columns BEFORE you include the counter_cache statement in the model. Once in the model, the columns are read only.

Rajive Jain
  • 758
  • 6
  • 7
2

To avoid read-only errors while running this migration, you should use reset_counters:

Video.find_each do |video|
  Video.reset_counters video.id, :video_votes
end
stereoscott
  • 13,309
  • 4
  • 33
  • 34
  • The second argument to the `reset_counters` method needs to be the name of the association, not the name of the counter_cache column, so it should be: `Video.reset_counters video.id, :video_votes` – Andrea Singh Apr 17 '13 at 23:57
  • `reset_counters` is now deprecated – ahnbizcad Sep 15 '14 at 17:27
  • 1
    @gwho I think it's still there... https://github.com/rails/rails/blob/master/activerecord/lib/active_record/counter_cache.rb#L20 – stereoscott Sep 15 '14 at 21:14
0

Rewriting Rajive Jain's solution :

Remove :counter_cache => true statement from the model file.

Rerun the migration : rake db:migrate

Add the counter_cache statement in your model : :counter_cache => true

Justin D.
  • 4,946
  • 5
  • 36
  • 69