¿Determinar qué atributos se cambiaron en la devolución de llamada after_save de Rails?

Resuelto modulaaron asked hace 14 años • 7 respuestas

Estoy configurando una devolución de llamada after_save en mi observador de modelo para enviar una notificación solo si el atributo publicado del modelo se cambió de falso a verdadero. ¿Desde que métodos como estos cambiaron? solo son útiles antes de guardar el modelo, la forma en que estoy intentando hacerlo actualmente (y sin éxito) 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 usando devoluciones de llamada de observador de modelo (para no contaminar el código de mi controlador)?

modulaaron avatar Oct 05 '10 14:10 modulaaron
Aceptado

Rieles 5.1+

Usar saved_change_to_published?:

class SomeModel < ActiveRecord::Base
  after_update :send_notification_after_change

  def send_notification_after_change
    Notification.send(…) if (saved_change_to_published? && self.published == true)
  end

end

O si lo prefieres, saved_change_to_attribute?(:published).

Rieles 3–5.1

Advertencia

Este enfoque funciona a través de Rails 5.1 (pero está obsoleto en 5.1 y tiene cambios importantes en 5.2). Puede leer sobre el cambio en esta solicitud de extracción .

En su after_updatefiltro sobre el modelo puede utilizar _changed?el descriptor de acceso. 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.

Radek Paviensky avatar Oct 05 '2010 08:10 Radek Paviensky

Para aquellos que quieran conocer los cambios que acaban de realizar en una after_savedevolución de llamada:

Rieles 5.1 y superiores

model.saved_changes

Rieles < 5,1

model.previous_changes

Consulte también: http://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-previous_changes

Jacek Głodek avatar Dec 18 '2013 12:12 Jacek Głodek

Para cualquiera que vea esto más adelante, ya que actualmente (agosto de 2017) encabeza Google: vale la pena mencionar que este comportamiento se modificará en Rails 5.2 y tiene advertencias de obsolescencia a partir de Rails 5.1, ya que ActiveModel::Dirty cambió un poco. .

¿Qué cambio?

Si está utilizando attribute_changed?el método en las after_*devoluciones de llamada, verá una advertencia como:

ADVERTENCIA DE DEPRECACIÓN: El comportamiento de attribute_changed?las devoluciones de llamada internas y posteriores cambiará en la próxima versión de Rails. El nuevo valor de retorno reflejará el comportamiento de llamar al método después savedel retorno (por ejemplo, lo opuesto a lo que devuelve ahora). Para mantener el comportamiento actual, utilice saved_change_to_attribute?en su lugar. (llamado desde some_callback en /PATH_TO/app/models/user.rb:15)

Como se menciona, puedes solucionar este problema fácilmente reemplazando la función con saved_change_to_attribute?. Así, por ejemplo, name_changed?se convierte en saved_change_to_name?.

Del mismo modo, si estás usando attribute_changepara obtener los valores de antes y después, esto también cambia y arroja lo siguiente:

ADVERTENCIA DE DEPRECACIÓN: El comportamiento de attribute_changelas devoluciones de llamada internas y posteriores cambiará en la próxima versión de Rails. El nuevo valor de retorno reflejará el comportamiento de llamar al método después savedel retorno (por ejemplo, lo opuesto a lo que devuelve ahora). Para mantener el comportamiento actual, utilice saved_change_to_attributeen su lugar. (llamado desde some_callback en /PATH_TO/app/models/user.rb:20)

Nuevamente, como menciona, el método cambia de nombre al saved_change_to_attributeque devuelve ["old", "new"]. o use saved_changes, que devuelve todos los cambios y se puede acceder a ellos como saved_changes['attribute'].

Frederik Spang avatar Aug 03 '2017 19:08 Frederik Spang

En caso de que puedas hacer esto before_saveen lugar de after_save, podrás 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

zeacuss avatar May 27 '2012 11:05 zeacuss