through references rails many has_one has_many has_and_belongs_to_many has example cache belongs and ruby-on-rails counter-cache

ruby-on-rails - references - rails has_one through



Problema con la implementación de counter_cache (2)

¡Me estoy haciendo abortar el rastrillo! ... posts_count está marcado como ''solo errores''.

Tengo dos modelos: usuario y post.

users has_many posts. posts belongs_to :user, :counter_cache => true

Tengo una migración que agrega la columna posts_count a la tabla de usuarios y luego calcula y registra el número actual de publicaciones por usuario.

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

Cuando ejecuto la migración me sale el error. Esto está bastante claro, por supuesto, y si elimino la declaración: counter_cache del modelo de publicaciones, por ejemplo

belongs_to :user

la migración funciona bien. Obviamente, esto no tiene sentido porque realmente no podría implementarlo de esta manera. ¿Qué me estoy perdiendo?


Debería usar User.reset_counters para hacer esto. Además, recomendaría usar find_each lugar de each porque find_each la colección en lotes en lugar de todos a la vez.

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


OK, la documentación dice:

Las columnas de caché de contador se agregan a la lista del modelo que contiene los atributos de solo lectura a través de attr_readonly.

Creo que esto es lo que sucede: usted declara el contador en la definición del modelo, lo que hace que el atributo "posts_count" sea de solo lectura. Luego, en la migración, intenta actualizarlo directamente, lo que da como resultado el error que menciona.

La solución rápida y sucia es eliminar la declaración de counter_cache del modelo, ejecutar la migración (para agregar la columna requerida a la base de datos Y llenarla con los conteos de publicaciones actuales), y luego volver a agregar la declaración counter_cache a el modelo. Debería funcionar pero es desagradable y requiere intervención manual durante la migración, no es una buena idea.

Encontré esta publicación de blog que sugiere alterar la lista de atributos de solo lectura del modelo durante la migración, está un poco en suspenso, pero es posible que desee intentarlo.