ruby-on-rails ruby-on-rails-4 model callback observer-pattern

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 de save (por ejemplo, lo contrario de lo que devuelve ahora). Para mantener el comportamiento actual, use saved_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 de save (por ejemplo, lo contrario de lo que devuelve ahora). Para mantener el comportamiento actual, use saved_change_to_attribute en saved_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 .