ruby on rails - Determine qué atributos se cambiaron en Rails after_save callback?
ruby-on-rails ruby-on-rails-4 (8)
En caso de que pueda hacer esto en before_save
lugar de after_save
, podrá usar esto:
self.changed
devuelve una matriz de todas las columnas modificadas en este registro.
también puedes usar:
self.changes
que devuelve un hash de columnas que cambiaron y resultados antes y después como matrices
Estoy configurando una devolución de llamada after_save en mi modelo de observador para enviar una notificación solo si el atributo publicado del modelo se cambió de falso a verdadero. Dado que los métodos como el cambio? solo son útiles antes de que se guarde el modelo, la forma en que actualmente (y sin éxito) trato de hacerlo es la siguiente:
def before_save(blog)
@og_published = blog.published?
end
def after_save(blog)
if @og_published == false and blog.published? == true
Notification.send(...)
end
end
¿Alguien tiene alguna sugerencia sobre la mejor manera de manejar esto, preferiblemente utilizando devoluciones de llamada del observador modelo (para no contaminar mi código de controlador)?
En su filtro after_update
en el modelo, ¿ puede usar _changed?
acceso (al menos en Rails 3, no estoy seguro para Rails 2). Así por ejemplo:
class SomeModel < ActiveRecord::Base
after_update :send_notification_after_change
def send_notification_after_change
Notification.send(...) if (self.published_changed? && self.published == true)
end
end
Simplemente funciona.
Estoy usando esto para extraer un hash con los nuevos valores de atributo, lo cual es útil para actualizar otros modelos
attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash}
los
attr[1].last == false
es necesario cuando el nuevo valor es false
, donde la asignación devuelve falso y no se devuelve "hash".
Creo que hay una manera más fácil, soy nuevo en los rieles
La respuesta "seleccionada" no funcionó para mí. Estoy usando Rails 3.1 con CouchRest :: Model (basado en el modelo activo). El _changed?
los métodos no devuelven verdadero para los atributos modificados en el gancho after_update
, solo en el gancho before_update
. Pude hacer que funcionara usando el (nuevo?) around_update
hook:
class SomeModel < ActiveRecord::Base
around_update :send_notification_after_change
def send_notification_after_change
should_send_it = self.published_changed? && self.published == true
yield
Notification.send(...) if should_send_it
end
end
Para aquellos que quieren saber los cambios después de guardarlos, debes usar
model.previous_changes
esto funciona como model.change
pero funciona aún después de model.save
, etc. Encontré esta information útil así que tal vez tú también lo harás.
En Rails 5.1+ esto está en desuso. Use saved_changes
en callbacks saved_changes
en after_save
lugar.
Para cualquiera que vea esto más adelante, como actualmente (agosto de 2017) encabeza google: vale la pena mencionar que este comportamiento se verá alterado en Rails 5.2 y tendrá advertencias de degradación a partir de Rails 5.1, ya que ActiveModel::Dirty cambió un poco .
¿Qué cambio?
Si está usando attribute_changed?
método en after_*
-callbacks, verá una advertencia como:
ADVERTENCIA DE DEPRESIÓN: ¿El comportamiento de
attribute_changed?
dentro de las devoluciones de llamadas cambiará en la próxima versión de Rails. El nuevo valor de retorno reflejará el comportamiento de llamar al método después desave
(por ejemplo, lo contrario de lo que devuelve ahora). Para mantener el comportamiento actual, usesaved_change_to_attribute?
en lugar. (llamado desde some_callback at /PATH_TO/app/models/user.rb:15)
Como se menciona, ¿podría arreglar esto fácilmente reemplazando la función con saved_change_to_attribute?
. Entonces, por ejemplo, name_changed?
se convierte en saved_change_to_name?
.
Del mismo modo, si está utilizando el attribute_change
para obtener los valores before-after, esto también cambia y arroja lo siguiente:
ADVERTENCIA DE DEPRESIÓN: el comportamiento de
attribute_change
dentro de las devoluciones de llamada cambiará en la próxima versión de Rails. El nuevo valor de retorno reflejará el comportamiento de llamar al método después desave
(por ejemplo, lo contrario de lo que devuelve ahora). Para mantener el comportamiento actual, usesaved_change_to_attribute
ensaved_change_to_attribute
lugar. (llamado desde some_callback en /PATH_TO/app/models/user.rb:20)
De nuevo, como se menciona, el método cambia el nombre a saved_change_to_attribute
que devuelve ["old", "new"]
. o use saved_changes
, que devuelve todos los cambios, y se puede acceder a ellos como saved_changes[''attribute'']
.
Usted acaba de agregar un descriptor de acceso que define lo que cambia
class Post < AR::Base
attr_reader :what_changed
before_filter :what_changed?
def what_changed?
@what_changed = changes || []
end
after_filter :action_on_changes
def action_on_changes
@what_changed.each do |change|
p change
end
end
end
puede agregar una condición al after_update
así:
class SomeModel < ActiveRecord::Base
after_update :send_notification, if: :published_changed?
...
end
no es necesario agregar una condición dentro del método send_notification
.