2009-10-19 14 views
71

Mi piacerebbe creare una funzione di callback nei binari che viene eseguita dopo il salvataggio di un modello.Come rilevare le modifiche degli attributi dal modello?

Ho questo modello, rivendicazione che ha un attributo 'status', che cambia a seconda dello stato del credito, valori possibili sono pendenti, approvato, approvato, respinto

Il database ha 'stato' con il default valore di 'in sospeso'.

Vorrei eseguire determinate attività dopo che il modello è stato creato la prima volta o aggiornato da uno stato a un altro, a seconda dello stato da cui viene modificato.

La mia idea è quella di avere una funzione nel modello:

after_save :check_state 

    def check_state 
     # if status changed from nil to pending (created) 
     do this 

     # if status changed from pending to approved 
     performthistask 
    end 

La mia domanda è come faccio assegno per il valore precedente prima del cambiamento all'interno del modello?

risposta

148

si dovrebbe guardare a modulo ActiveModel::Dirty: Si dovrebbe essere in grado di eseguire le azioni seguenti del modello di rivendicazione:

claim.status_changed? # returns true if 'status' attribute has changed 
claim.status_was  # returns the previous value of 'status' attribute 
claim.status_change # => ['old value', 'new value'] returns the old and 
         # new value for 'status' attribute 

claim.name = 'Bob' 
claim.changed # => ["name"] 
claim.changes # => {"name" => ["Bill", "Bob"]} 

Oh! le gioie di Rails!

+4

Questo non funzionerà dopo il salvataggio del modello, che è quello che ha chiesto. –

+3

@TomRossi, le chiamate 'dirty' funzionano in' after_save' (sia in Rails 2.3 che in 3.x). L'ho usato diverse volte. –

+8

@TomRossi, i flag dirty vengono ripristinati dopo il commit, quindi non saranno disponibili nei callback 'after_commit' introdotti in Rails 3.x. Certamente funzioneranno in 'after_save'. –

3

vi consiglio di dare un'occhiata a uno dei plugin macchina a stati disponibili:

O uno ti consente di stati di impostazione e le transizioni tra stati. Modo molto utile e semplice per gestire le tue esigenze.

+0

Provo a provare il rubyist-aasm. Diciamo che ho classe rivendicazione : enter_pending def enter_pending Notifier.deliver_pending_notification (self) fine fine E il mio campo di stato nel mio database ha il valore predefinito di "in sospeso". Se dovessi eseguire un Claim.create senza compilare il campo dello stato (in modo che venga eseguito 'in sospeso'), AASM eseguirà il metodo 'enter_pending'? –

33

è possibile utilizzare questo

self.changed 

è restituire una matrice di tutte le colonne che hanno cambiato in questo disco

è anche possibile utilizzare

self.changes 

che restituisce un hash di colonne che hanno cambiato e prima e dopo i risultati come array

+4

Solo una piccola nota per dire che non è necessario usare' self' su questi - puoi semplicemente dire 'cambiato' e 'cambiamenti'. – user664833

0

Ho visto aumentare la domanda in molti posti, quindi ho scritto un piccolo rubygem per renderlo un po 'più bello (ed evitare un milione se/else dichiarazioni ovunque): https://github.com/ronna-s/on_change. Spero che questo aiuti.

0

Sarà molto meglio utilizzare una soluzione ben testata come la gemma state_machine.

Problemi correlati