Configuración usando un ejemplo simple: tengo 1 tabla ( Totals
) que contiene la suma de la amount
columna de cada registro en una segunda tabla ( Things
).
Cuando thing.amount
se actualiza, me gustaría simplemente agregar la diferencia entre el valor anterior y el nuevo valor a total.sum
.
Ahora mismo estoy restando self.amount
durante before_update
y sumando self.amount
durante after_update
. Esto deposita demasiada confianza en que la actualización se realice correctamente.
Restricción: no quiero simplemente volver a calcular la suma de todas las transacciones.
Pregunta: Simplemente, me gustaría acceder al valor original durante una after_update
devolución de llamada. ¿Qué formas se te han ocurrido para hacer esto?
Actualización: voy con la idea de Luke Francl. Durante una after_update
devolución de llamada, todavía tiene acceso a los self.attr_was
valores, que es exactamente lo que quería. También decidí ir con una after_update
implementación porque quiero mantener este tipo de lógica en el modelo. De esta manera, no importa cómo decida actualizar las transacciones en el futuro, sabré que estoy actualizando la suma de las transacciones correctamente. Gracias a todos por sus sugerencias de implementación.
Algunas otras personas están mencionando envolver todo esto en una transacción, pero creo que eso está hecho para usted; solo necesita activar la reversión generando una excepción para errores en las devoluciones de llamada after_ *.
Ver http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
fuente
Agregar "_was" a su atributo le dará el valor anterior antes de guardar los datos.
Estos métodos se denominan métodos sucios .
¡Salud!
fuente
Para obtener todos los campos modificados, con sus valores nuevos y antiguos, respectivamente:
person = Person.create!(:name => 'Bill') person.name = 'Bob' person.save person.changes # => {"name" => ["Bill", "Bob"]}
fuente
person.previous_changes
lugar deperson.changes
ActiveRecord :: Dirty es un módulo integrado en ActiveRecord para realizar un seguimiento de los cambios de atributos. Entonces puedes usar
thing.amount_was
para obtener el valor anterior.fuente
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.
fuente
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 before_update, al que luego puede acceder en after_update, sin embargo, esta no es una solución muy elegante.
fuente
Idea 1: Envuelva la actualización en una transacción de base de datos, de modo que si la actualización falla, su tabla de Totales no cambie: Documentos de Transacciones de ActiveRecord
Idea 2: guarde el valor anterior en @old_total durante el before_update.
fuente
Si desea obtener el valor de un campo en particular después de la actualización, puede usar el método field_before_last_save.
Example: u = User.last u.update(name: "abc") u.name_before_last_save will give you old value (before update value)
fuente