Question

Je la mise en place d'un rappel after_save dans mon observateur de modèle pour envoyer une notification que si le modèle de publié attribut a été changé de false à true. Étant donné que des méthodes telles que changé ne sont utiles avant que le modèle est enregistré, la façon dont je suis actuellement (et sans succès) en essayant de le faire est suit comme:

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

Est-ce que quelqu'un a des suggestions quant à la meilleure façon de gérer cela, en utilisant de préférence callbacks observateurs du modèle (pour ne pas polluer mon code de contrôleur)?

Était-ce utile?

La solution

Dans votre filtre after_update sur le modèle peut accesseur utilisation de _changed? (au moins dans Rails 3, pas sûr pour Rails 2). Ainsi, par exemple:

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

Il fonctionne.

Autres conseils

Pour ceux qui veulent connaître les changements viennent d'être faites dans un rappel after_save:

Rails 5.1 et plus

model.saved_changes

Rails <5.1

model.previous_changes

Voir aussi: http://api.rubyonrails.org /classes/ActiveModel/Dirty.html#method-i-previous_changes

Pour quiconque voir cela plus tard, comme actuellement (Aug. 2017) arrive en tête Google: Il est mentionner vaut la peine, que ce comportement sera modifié dans Rails 5.2 , et comporte des avertissements relatifs à l'obsolescence comme Rails 5.1, comme ActiveModel :: sale un peu changé.

Que dois-je changer?

Si vous utilisez la méthode de attribute_changed? dans les callbacks after_*, vous verrez un avertissement comme:

  

deprecation AVERTISSEMENT: Le comportement de attribute_changed? intérieur après callbacks vont changer dans la prochaine version de Rails. La nouvelle valeur de retour reflète le comportement d'appeler la méthode après save retour (par exemple, le contraire de ce qu'il retourne maintenant). Pour maintenir le comportement actuel, l'utilisation saved_change_to_attribute? à la place. (Appelé à partir de some_callback à /PATH_TO/app/models/user.rb:15)

Comme il mentionne, vous pouvez corriger cela facilement en remplaçant la fonction avec saved_change_to_attribute?. Ainsi, par exemple, name_changed? devient saved_change_to_name?.

De même, si vous utilisez le attribute_change pour obtenir les avant-après les valeurs, cela change aussi bien et jette les éléments suivants:

  

deprecation AVERTISSEMENT: Le comportement de attribute_change intérieur après callbacks vont changer dans la prochaine version de Rails. La nouvelle valeur de retour reflète le comportement d'appeler la méthode après save retour (par exemple, le contraire de ce qu'il retourne maintenant). Pour maintenir le comportement actuel, l'utilisation saved_change_to_attribute à la place. (Appelé à partir de some_callback à /PATH_TO/app/models/user.rb:20)

Encore une fois, comme il le mentionne, la méthode change de nom pour saved_change_to_attribute qui retourne ["old", "new"]. ou l'utilisation saved_changes, qui renvoie tous les changements, et ceux-ci sont accessibles en saved_changes['attribute'].

Si vous pouvez le faire sur before_save au lieu de after_save, vous serez en mesure d'utiliser ceci:

self.changed

elle retourne un tableau de toutes les colonnes modifiées dans cet enregistrement.

vous pouvez également utiliser:

self.changes

qui retourne un hachage de colonnes qui a changé et avant et après les résultats sous forme de tableaux

Le « sélectionné » réponse ne fonctionne pas pour moi. J'utilise des rails 3.1 avec CouchRest :: Model (basé sur le modèle actif). Les méthodes de _changed? ne renvoient pas pour les attributs modifiés dans le crochet after_update, seulement dans le crochet de before_update. J'ai pu l'obtenir au travail en utilisant le (nouveau?) Crochet 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

vous pouvez ajouter une condition à la after_update comme ceci:

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

  ...
end

il n'y a pas besoin d'ajouter une condition dans la méthode de send_notification lui-même.

J'utilise ceci pour extraire un hachage avec les nouvelles valeurs d'attributs, ce qui est utile pour moi de mettre à jour les autres modèles

attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash}

attr[1].last == false

est nécessaire lorsque la nouvelle valeur est false, où les retours d'affectation faux et « hachage » est pas retourné.

Je suppose qu'il ya un moyen plus facile, je suis nouveau sur les rails

Vous venez d'ajouter un accesseur qui définissent ce que vous modifiez

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top