Utilizzando ActiveRecord, c'è un modo per ottenere i vecchi valori di un record durante after_update

StackOverflow https://stackoverflow.com/questions/607069

Domanda

Installazione usando un semplice esempio: ho 1 tabella ( totali ) che contiene la somma della colonna importo di ciascun record in una seconda tabella ( Things ).

Quando viene aggiornato un thing.amount , vorrei semplicemente aggiungere la differenza tra il vecchio valore e il nuovo valore in total.sum .

In questo momento sto sottraendo self.amount durante before_update e aggiungendo self.amount durante after_update . Questo rende MODO troppa fiducia nell'aggiornamento riuscito.

Vincolo: non voglio semplicemente ricalcolare la somma di tutte le transazioni.

Domanda: semplicemente, vorrei accedere al valore originale durante un callback after_update . In che modo ti sei inventato per farlo?

Aggiornamento: vado con l'idea di Luke Francl. Durante un callback after_update hai ancora accesso ai valori self.attr_was che è esattamente quello che volevo. Ho anche deciso di utilizzare un'implementazione after_update perché voglio mantenere questo tipo di logica nel modello. In questo modo, indipendentemente da come deciderò di aggiornare le transazioni in futuro, saprò che sto aggiornando correttamente la somma delle transazioni. Grazie a tutti per i suggerimenti di implementazione.

È stato utile?

Soluzione

Idem quello che dicono tutti sulle transazioni.

Detto questo ...

ActiveRecord a partire da Rails 2.1 tiene traccia dei valori degli attributi di un oggetto. Quindi se hai un attributo total , avrai un metodo total_changed? e un metodo total_was che restituisce il vecchio valore.

Non è necessario aggiungere nulla al tuo modello per tenerne traccia.

Aggiornamento: ecco la documentazione per ActiveModel :: Dirty come richiesto.

Altri suggerimenti

Alcune altre persone stanno citando il wrapping di tutto questo in una transazione, ma penso che sia stato fatto per te; devi solo attivare il rollback sollevando un'eccezione per gli errori nei callback after_ *.

Vedi http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

  

L'intera catena di callback di un salvataggio, salvataggio! o distruzione delle chiamate viene eseguita all'interno di una transazione. Ciò include gli hook after_ *. Se tutto va bene, viene eseguito un COMMIT una volta completata la catena.

     

Se un callback before_ * annulla l'azione, viene emesso un ROLLBACK. Puoi anche attivare un ROLLBACK che solleva un'eccezione in uno qualsiasi dei callback, inclusi gli hook after_ *. Si noti, tuttavia, che in quel caso il client deve esserne consapevole perché un normale salvataggio solleverà tale eccezione invece di restituire silenziosamente false.

Aggiunta di " _was " al tuo attributo ti darà il valore precedente prima di salvare i dati.

Questi metodi sono chiamati metodi sporchi .

Cheers!

Per ottenere tutti i campi modificati, rispettivamente con i loro vecchi e nuovi valori:

person = Person.create!(:name => 'Bill')
person.name = 'Bob'
person.save
person.changes        # => {"name" => ["Bill", "Bob"]}

ActiveRecord :: Dirty è un modulo integrato in ActiveRecord per il tracciamento le modifiche agli attributi. Quindi puoi usare thing.amount_was per ottenere il vecchio valore.

Aggiungi questo al tuo modello:

def amount=(new_value)
    @old_amount = read_attribute(:amount)
    write_attribute(:amount,new_value)
end

Quindi usa @old_amount nel tuo codice after_update.

In primo luogo, dovresti farlo in una transazione per assicurarti che i tuoi dati vengano scritti insieme.

Per rispondere alla tua domanda, puoi semplicemente impostare una variabile membro sul vecchio valore in before_update, a cui puoi accedere in after_update, tuttavia questa non è una soluzione molto elegante.

Idea 1: avvolgere l'aggiornamento in una transazione del database, in modo che se l'aggiornamento non riesce la tabella dei totali non viene modificata: Documenti Transazioni ActiveRecord

Idea 2: riponi il vecchio valore in @old_total durante il before_update.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top