Domanda

Sto impostando una richiamata after_save nel mio osservatore del modello per inviare una notifica solo se il modello pubblicato l'attributo è stato modificato da falso a vero.Poiché metodi come cambiato? sono utili solo prima che il modello venga salvato, il modo in cui sto attualmente (e senza successo) tentando di farlo è il seguente:

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

Qualcuno ha qualche suggerimento sul modo migliore per gestire questo problema, preferibilmente utilizzando i callback dell'osservatore del modello (in modo da non inquinare il codice del mio controller)?

È stato utile?

Soluzione

Nel tuo after_update filtra in base al modello tu Potere utilizzo _changed? accessor (almeno in Rails 3, non sono sicuro per Rails 2).Quindi ad esempio:

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

Funziona e basta.

Altri suggerimenti

Per chi vuole conoscere le modifiche appena apportate in an after_save richiamare:

Rails 5.1 e versioni successive

model.saved_changes

Rotaie < 5.1

model.previous_changes

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

A chiunque lo vedrà più tardi, come è attualmente (Agosto).2017) supera Google:Vale la pena ricordare che questo comportamento verrà modificato Rotaie 5.2, e presenta avvisi di deprecazione a partire da Rails 5.1, come Modello attivo::Sporco cambiato un po'.

Cosa cambio?

Se stai usando attribute_changed? metodo nel after_*-callback, vedrai un avviso come:

AVVISO DI DEPRECAZIONE:Il comportamento di attribute_changed? i callback interni e successivi cambieranno nella prossima versione di Rails.Il nuovo valore restituito rifletterà il comportamento della chiamata successiva al metodo save restituito (es.il contrario di ciò che restituisce adesso).Per mantenere il comportamento corrente, utilizzare saved_change_to_attribute? Invece.(chiamato da some_callback su /PATH_TO/app/models/user.rb:15)

Come menzionato, puoi risolvere questo problema facilmente sostituendo la funzione con saved_change_to_attribute?.Quindi, ad esempio, name_changed? diventa saved_change_to_name?.

Allo stesso modo, se stai utilizzando il file attribute_change per ottenere i valori prima-dopo, anche questo cambia e genera quanto segue:

AVVISO DI DEPRECAZIONE:Il comportamento di attribute_change i callback interni e successivi cambieranno nella prossima versione di Rails.Il nuovo valore restituito rifletterà il comportamento della chiamata successiva al metodo save restituito (es.il contrario di ciò che restituisce adesso).Per mantenere il comportamento corrente, utilizzare saved_change_to_attribute Invece.(chiamato da some_callback su /PATH_TO/app/models/user.rb:20)

Ancora una volta, come menzionato, il metodo cambia nome in saved_change_to_attribute che ritorna ["old", "new"].o utilizzare saved_changes, che restituisce tutte le modifiche ed è possibile accedervi come saved_changes['attribute'].

Nel caso in cui tu possa farlo before_save invece di after_save, potrai utilizzare questo:

self.changed

restituisce un array di tutte le colonne modificate in questo record.

puoi anche usare:

self.changes

che restituisce un hash di colonne modificate e i risultati prima e dopo come matrici

La risposta "selezionata" non ha funzionato per me.Sto utilizzando i binari 3.1 con CouchRest::Model (basato su Active Model).IL _changed? i metodi non restituiscono true per gli attributi modificati nel file after_update gancio, solo nel before_update gancio.Sono riuscito a farlo funzionare utilizzando il (nuovo?) around_update gancio:

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

puoi aggiungere una condizione al file after_update così:

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

  ...
end

non è necessario aggiungere una condizione all'interno del file send_notification metodo stesso.

Lo sto usando per estrarre un hash con i nuovi valori degli attributi, che mi è utile per aggiornare altri modelli

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

IL

attr[1].last == false

è necessario quando è presente un nuovo valore false, dove l'assegnazione restituisce false e "hash" non viene restituito.

Immagino che ci sia un modo più semplice, sono nuovo ai binari

Devi solo aggiungere una funzione di accesso che definisce ciò che cambi

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top