Проблема с реализацией counter_cache

Я получаю "rake aborted!... posts_count помечен как readonly '.

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

users has_many posts.

posts belongs_to :user, :counter_cache => true

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

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 из модели сообщений, например.

belongs_to :user

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

Ответ 1

Вы должны использовать 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

Ответ 2

ОК, в документации указано:

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

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

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

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