validations validates validate rails example callbacks after_create after ruby-on-rails activerecord model callback

ruby on rails - validates - Usando ActiveRecord, ¿hay alguna forma de obtener los valores anteriores de un registro durante after_update?



rails validate if (8)

Configuración usando un ejemplo simple: tengo 1 tabla ( Totals ) que contiene la suma de la columna de amount de cada registro en una segunda tabla ( Things ).

Cuando se actualiza un thing.amount , me gustaría simplemente agregar la diferencia entre el valor anterior y el nuevo valor a total.sum .

En este momento estoy restando self.amount durante before_update y agregando self.amount durante after_update . Esto pone MUCHA confianza en la actualización exitosa.

Restricción: no quiero simplemente recalcular la suma de todas las transacciones.

Pregunta: Simplemente, me gustaría acceder al valor original durante una after_update llamada after_update . ¿De qué manera se te ocurrió esto?

Actualización: voy con la idea de Luke Francl. Durante una after_update llamada after_update usted todavía tiene acceso a los valores self.attr_was que es exactamente lo que yo quería. También decidí ir con una implementación after_update porque quiero mantener este tipo de lógica en el modelo. De esta forma, sin importar cómo decida actualizar las transacciones en el futuro, sabré que actualizo la suma de las transacciones correctamente. Gracias a todos por sus sugerencias de implementación.



Agregue esto a su modelo:

def amount=(new_value) @old_amount = read_attribute(:amount) write_attribute(:amount,new_value) end

Luego use @old_amount en su código after_update.


Algunas otras personas están mencionando envolver todo esto en una transacción, pero creo que eso se ha hecho por ti; solo necesita desencadenar la reversión al generar una excepción para los errores en las devoluciones de llamada after_ *.

Ver http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

Toda la cadena de devolución de llamada de una llamada de guardar, guardar, o destruir se ejecuta dentro de una transacción. Eso incluye after_ * hooks. Si todo va bien, se ejecuta COMMIT una vez que la cadena se ha completado.

Si una devolución de llamada before_ * cancela la acción, se genera un ROLLBACK. También puede desencadenar un ROLLBACK que genere una excepción en cualquiera de las devoluciones de llamada, incluidos after_ * hooks. Sin embargo, tenga en cuenta que, en ese caso, el cliente debe tenerlo en cuenta porque un guardado ordinario generará dicha excepción en lugar de devolver falsamente.


En primer lugar, debe hacer esto en una transacción para asegurarse de que sus datos se escriban juntos.

Para responder a su pregunta, puede establecer una variable miembro en el valor anterior en la actualización anterior, a la que puede acceder en la actualización posterior, sin embargo, esta no es una solución muy elegante.


Idea 1: ajuste la actualización en una transacción de base de datos, de modo que si la actualización falla, su tabla de totales no se modifique : documentos de transacciones ActiveRecord

Idea 2: oculte el valor anterior en @old_total durante el before_update.


Lo mismo que todo el mundo está diciendo sobre las transacciones.

Eso dijo ...

ActiveRecord a partir de Rails 2.1 realiza un seguimiento de los valores de atributo de un objeto. Entonces, si tiene un atributo total , ¿tendrá un total_changed? método y un método total_was que devuelve el valor anterior.

No es necesario agregar nada a su modelo para realizar un seguimiento de esto nunca más.

Actualización: aquí está la documentación para ActiveModel::Dirty según lo solicitado.


Para obtener todos los campos modificados, con sus valores antiguo y nuevo, respectivamente:

person = Person.create!(:name => ''Bill'') person.name = ''Bob'' person.save person.changes # => {"name" => ["Bill", "Bob"]}


ActiveRecord::Dirty es un módulo que está integrado en ActiveRecord para el seguimiento de cambios de atributos. Entonces puedes usar thing.amount_was para obtener el valor anterior.