counter_cache实现的问题

时间:2010-11-28 04:38:45

标签: ruby-on-rails counter-cache

我得到'耙子流产! ... posts_count标记为只读'错误。

我有两个模型:用户和帖子。

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

当我运行迁移时,我收到错误。这当然非常明确,如果我从posts模型中删除:counter_cache声明,例如

belongs_to :user

迁移运行良好。显然,这没有意义,因为你无法以这种方式真正实现它。我错过了什么?

2 个答案:

答案 0 :(得分:97)

您应该使用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

答案 1 :(得分:3)

好的,文档说明:

  

计数器缓存列已添加到   包含模型的只读列表   属性通过attr_readonly。

我认为这就是:在模型的定义中声明计数器,从而将“posts_count”属性设置为只读。然后,在迁移过程中,您尝试直接更新它,导致您提到的错误。

快速而肮脏的解决方案是从模型中删除counter_cache声明,运行迁移(为了将所需的列添加到数据库并使用当前的帖子计数填充它),然后重新添加对模型的counter_cache声明。应该工作但是很讨厌并且在迁移期间需要人工干预 - 这不是一个好主意。

我发现this blog post建议在迁移过程中更改模型的只读属性列表,这有点啰嗦,但您可能想尝试一下。