Проблема с реализацией counter_cache - PullRequest
43 голосов
/ 28 ноября 2010

Грабли прерваны! ... posts_count помечается как ошибки только для чтения.

У меня есть две модели: пользователь и пост.

users has_many posts.

posts belongs_to :user, :counter_cache => true

У меня есть миграция, которая добавляет столбец posts_count в таблицу пользователей, а затем вычисляет и записывает текущее количество сообщений на пользователя.

self.up
  add_column :users, :posts_count, :integer, :default => 0

  User.reset_column_information
  User.all.each do |u|
    u.update_attribute( :posts_count, u.posts.count)
  end
end

когда я запускаю миграцию, я получаю сообщение об ошибке. Конечно, это довольно четко, и если я удалю объявление: counter_cache из модели posts, например,

belongs_to :user

миграция проходит нормально. Это, очевидно, не имеет смысла, потому что вы не могли бы реализовать это таким образом. Чего мне не хватает?

Ответы [ 2 ]

97 голосов
/ 28 ноября 2010

Вы должны использовать User.reset_counters для этого. Кроме того, я бы порекомендовал использовать find_each вместо each, поскольку он будет повторять коллекцию в пакетном режиме вместо всех сразу.

self.up
  add_column :users, :posts_count, :integer, :default => 0

  User.reset_column_information
  User.find_each do |u|
    User.reset_counters u.id, :posts
  end
end
3 голосов
/ 28 ноября 2010

ОК, документация гласит:

Столбцы кэша счетчика добавляются в список доступных только для чтения атрибутов модели с помощью attr_readonly.

Я думаю, это то, чтопроисходит: вы объявляете счетчик в определении модели, таким образом атрибут «posts_count» становится доступным только для чтения.Затем в процессе миграции вы пытаетесь обновить его напрямую, что приводит к указанной вами ошибке.

Быстрое и грязное решение состоит в том, чтобы удалить объявление counter_cache из модели, запустить миграцию (чтобыдобавьте необходимый столбец в базу данных и заполните его текущим количеством сообщений), а затем повторно добавьте объявление counter_cache в модель.Должно работать, но неприятно и требует ручного вмешательства во время миграции - не очень хорошая идея.

Я нашел это сообщение в блоге , которое предлагает изменить список атрибутов модели только для чтения во время миграции,он немного устарел, но вы можете попробовать.

...