Este post tiene dos finalidades: apuntar un detalle de Rails para que nunca más se me olvide y quejarme(en vano) ya que, a veces, Rails tiene cosas que me resulta dificil entender como es el caso que nos ocupa. Veamos el siguiente fragmento de una inocente migration.
def self.up add_column 'users', 'energy', :integer, :null => false, :default => 0 signup_energy = 20 User.find(:all).each do |u| u.update_attribute('energy', signup_energy) end end
Parece lógico pensar que la energía de los usuarios al finalizar la migration será 20. Craso error. La nergía es 0, el valor por defecto. La razón es que la clase User está inicializada antes de la ejecución de add_column y por tanto en el momento de actualizar el atributo con update_attribute no existe un campo energy. SI hubiesemos escrito algo como…
User.find(:all).each do |u| u.energy = signup_energy u.save end
...obtendríamos una simpatica excepción. No hay problema, miramos la documentación de Migration y nos encontramos con un apartado que habla de esto y nos indica que debemos invocar el método reset_column_information para poder actualizar los accessors de las diferentes propiedades de la clase.
User.reset_column_information User.find(:all).each { |u| u.update_attribute('energy', signup_energy) }
Todo esto está muy bien, pero a mi me asalta una duda. Si esto es así, por qué demonios no se invoca esa función cuando se modifica una columna de una tabla de forma transparente al programador.
En fin. Es lo que hay.