Frage

Ich gründe einen after_save Rückruf in meinem Modell Beobachter auf nur eine Benachrichtigung zu senden, wenn das Modell der veröffentlicht Attribut von false auf true geändert wurde. Da Methoden wie geändert nur dann sinnvoll ist, bevor das Modell gespeichert wird, so, wie ich zur Zeit bin (und erfolglos) versucht, so zu tun, ist wie folgt:

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

Hat jemand irgendwelche Vorschläge in Bezug auf die beste Art und Weise zu handhaben, vorzugsweise Modell Beobachter Rückrufe verwendet (um nicht meinen Controller-Code zu verschmutzen)?

War es hilfreich?

Lösung

In Ihrem after_update Filter auf dem Modell, das Sie auf können Verwendung _changed? Accessor (zumindest in Rails 3, nicht sicher für Rails 2). So zum Beispiel:

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

Es funktioniert einfach.

Andere Tipps

Für diejenigen, die die Änderungen nur gemacht in einem after_save Rückruf wissen wollen:

Rails 5.1 und größer

model.saved_changes

Rails <5.1

model.previous_changes

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

Für jeden, dies später zu sehen, wie es zur Zeit (August 2017) Tops Google: Es ist erwähnenswert, dass dieses Verhalten geändert wird, wird in Rails 5.2 , und hat deprecation Warnungen von Rails 5.1, wie ActiveModel :: Schmutzige ein wenig verändert.

Was ändere ich?

Wenn Sie attribute_changed? Methode in den after_*-Rückrufe verwenden, erhalten Sie eine Warnung wie sehen:

  

deprecation WARNUNG: Das Verhalten von attribute_changed? innerhalb der nach Rückrufe werden in der nächsten Version von Rails werden zu ändern. Der neue Rückgabewert wird das Verhalten der Aufruf der Methode reflektieren nach save zurück (zum Beispiel das Gegenteil von dem, was es gibt jetzt). Um das aktuelle Verhalten beizubehalten, verwendet saved_change_to_attribute? statt. (Genannt von some_callback bei /PATH_TO/app/models/user.rb:15)

Wie erwähnt, können Sie diese leicht beheben, indem Sie die Funktion mit saved_change_to_attribute? ersetzen. So zum Beispiel, name_changed? wird saved_change_to_name?.

Ebenso, wenn Sie die attribute_change verwenden die Vorher-Nachher-Werte zu erhalten, diese Änderungen auch und führt den folgenden:

  

deprecation WARNUNG: Das Verhalten von attribute_change innerhalb der nach Rückrufe werden in der nächsten Version von Rails werden zu ändern. Der neue Rückgabewert wird das Verhalten der Aufruf der Methode reflektieren nach save zurück (zum Beispiel das Gegenteil von dem, was es gibt jetzt). Um das aktuelle Verhalten beizubehalten, verwendet saved_change_to_attribute statt. (Genannt von some_callback bei /PATH_TO/app/models/user.rb:20)

Auch hier, wie es erwähnt, ändert sich die Methode Namen saved_change_to_attribute die ["old", "new"] zurückgibt. oder Verwendung saved_changes, die alle um die Änderungen zurückgibt, und diese können als saved_changes['attribute'] zugegriffen werden.

Falls Sie diese auf before_save statt after_save tun können, werden Sie in der Lage sein, diese zu nutzen:

self.changed

es gibt ein Array aller geänderten Spalten in diesem Datensatz.

Sie können auch verwendet werden:

self.changes

, die einen Hash von Spalten kehren das geändert und vor und nach den Ergebnissen als Arrays

Die „ausgewählte“ Antwort nicht für mich arbeiten. Ich bin Schiene 3.1 mit CouchRest :: Modell (auf Basis Active-Modell) verwendet wird. Die _changed? Methoden nicht zurück wahr für geänderte Attribute im after_update Haken, nur in dem before_update Haken. Ich konnte es zur Arbeit kommen mit den (neuen?) around_update Haken:

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

können Sie eine Bedingung an die after_update wie so hinzufügen:

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

  ...
end

gibt es keine Notwendigkeit, eine Bedingung innerhalb der send_notification Methode selbst hinzuzufügen.

Ich bin mit diesem einen Hash mit den neuen Attributwerten zu extrahieren, was nützlich ist für mich andere Modelle zu aktualisieren

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

Die

attr[1].last == false

benötigt wird, wenn neuer Wert false ist, wo die Zuordnung false zurück und „Hash“ nicht zurückgegeben.

Ich denke, es ist ein einfacher Weg, ich bin neu auf Schienen

Sie fügen Sie einfach einen Accessor, die definieren, was Sie ändern

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top