Pregunta

Soy la creación de una devolución de llamada after_save en mi modelo de observador para enviar una notificación sólo si el modelo de publicó atributo fue cambiado de falso a verdadero. Dado que los métodos tales como cambiado sólo son útiles antes de guardar el modelo, la forma en que estoy actualmente (y sin éxito) tratando 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 en cuanto a la mejor manera de manejar esto, utilizando preferentemente las devoluciones de llamada modelo de observación (con el fin de no contaminar mi código controlador)?

¿Fue útil?

Solución

En su filtro after_update del modelo que puede de acceso de uso _changed? (al menos en los carriles 3, no está seguro de los carriles 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.

Otros consejos

Para los que quieren saber los cambios que acaba de hacer en una devolución de llamada after_save:

Barras de 5,1 y una mayor

model.saved_changes

Rieles <5,1

model.previous_changes

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

Para que nadie vea esto más adelante, ya que actualmente (Agosto 2017) encabeza Google: Vale la pena mencionar, que este comportamiento se altera en Rails 5.2 , y tiene como advertencias de obsolescencia de los carriles 5.1, como ActiveModel :: Dirty cambió un poco.

¿Qué puedo cambiar?

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

  

Deprecation ADVERTENCIA: El comportamiento de attribute_changed? dentro de devoluciones de llamada después se van a cambiar en la próxima versión de Rails. El nuevo valor de retorno reflejará el comportamiento de una llamada al método después volvió save (por ejemplo, lo contrario de lo que devuelve ahora). Para mantener el comportamiento actual, el uso saved_change_to_attribute? lugar. (Llamado a partir de some_callback en /PATH_TO/app/models/user.rb:15)

Como se menciona, se podría solucionar esto fácilmente mediante la sustitución de la función con saved_change_to_attribute?. Así, por ejemplo, se convierte en name_changed? saved_change_to_name?.

Del mismo modo, si usted está utilizando la attribute_change para obtener los valores de antes y después, esto cambia también y lanza la siguiente:

  

Deprecation ADVERTENCIA: El comportamiento de attribute_change dentro de devoluciones de llamada después se van a cambiar en la próxima versión de Rails. El nuevo valor de retorno reflejará el comportamiento de una llamada al método después volvió save (por ejemplo, lo contrario de lo que devuelve ahora). Para mantener el comportamiento actual, el uso saved_change_to_attribute lugar. (Llamado a partir de some_callback en /PATH_TO/app/models/user.rb:20)

De nuevo, como se menciona, el método cambia de nombre a saved_change_to_attribute que devuelve ["old", "new"]. o uso saved_changes, que devuelve todos los cambios, y estos pueden ser accedidos como saved_changes['attribute'].

En caso de que usted puede hacer esto en vez de before_save after_save, usted será capaz de utilizar este:

self.changed

devuelve una matriz de todas las columnas cambiado en este registro.

También puede usar:

self.changes

que devuelve un hash de columnas que cambió y antes y después de los resultados como matrices

La respuesta "seleccionado" no funcionó para mí. Estoy usando los carriles 3.1 con CouchRest :: Modelo (Basado en Modelo activo). Los métodos _changed? no devuelven cierto para los atributos modificados en el gancho after_update, sólo en el gancho before_update. Yo era capaz de conseguir que funcione con el (nuevo?) Gancho around_update:

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

Puede agregar una condición a la after_update este modo:

class SomeModel < ActiveRecord::Base
  after_update :send_notification, if: :published_changed?

  ...
end

no hay necesidad de añadir una condición dentro del método send_notification sí.

Estoy usando esto para extraer un hash con los nuevos valores de atributos, que es útil para mí 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}

La

attr[1].last == false

es necesaria cuando el nuevo valor es false, donde los rendimientos de asignación falsa y "control" no se devuelve.

Creo que hay una manera más fácil, soy nuevo en rieles

Usted acaba de añadir un descriptor de acceso que defina 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top