Konfiguracja za pomocą prostego przykładu: Mam 1 tabelę ( Totals
), która przechowuje sumę amount
kolumny każdego rekordu w drugiej tabeli ( Things
).
Kiedy a thing.amount
zostanie zaktualizowany, chciałbym po prostu dodać różnicę między starą wartością a nową wartością do total.sum
.
W tej chwili odejmuję w self.amount
trakcie before_update
i dodam w self.amount
trakcie after_update
. To zbytnie pokłada zaufanie w powodzeniu aktualizacji.
Ograniczenie: nie chcę po prostu ponownie obliczać sumy wszystkich transakcji.
Pytanie: Po prostu chciałbym uzyskać dostęp do oryginalnej wartości podczas after_update
wywołania zwrotnego. Jakie sposoby wymyśliłeś, aby to zrobić?
Aktualizacja: idę z pomysłem Luke'a Francla. Podczas after_update
oddzwonienia nadal masz dostęp do self.attr_was
wartości, które są dokładnie takie, jakie chciałem. Zdecydowałem się również na after_update
implementację, ponieważ chcę zachować tego rodzaju logikę w modelu. Dzięki temu bez względu na to, jak zdecyduję się aktualizować transakcje w przyszłości, będę wiedział, że poprawnie aktualizuję sumę transakcji. Dziękujemy wszystkim za sugestie dotyczące wdrożenia.
Niektórzy wspominają o zawarciu tego wszystkiego w transakcji, ale myślę, że to zrobiono dla ciebie; wystarczy wyzwolić wycofywanie, zgłaszając wyjątek dla błędów w wywołaniach zwrotnych after_ *.
Zobacz http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
źródło
Dołączenie „_was” do atrybutu da ci poprzednią wartość przed zapisaniem danych.
Metody te nazywane są metodami brudnymi .
Twoje zdrowie!
źródło
Aby uzyskać wszystkie zmienione pola, odpowiednio ze starymi i nowymi wartościami:
person = Person.create!(:name => 'Bill') person.name = 'Bob' person.save person.changes # => {"name" => ["Bill", "Bob"]}
źródło
person.previous_changes
zamiastperson.changes
ActiveRecord :: Dirty to moduł wbudowany w ActiveRecord do śledzenia zmian atrybutów. Możesz więc użyć,
thing.amount_was
aby uzyskać starą wartość.źródło
Dodaj to do swojego modelu:
def amount=(new_value) @old_amount = read_attribute(:amount) write_attribute(:amount,new_value) end
Następnie użyj @old_amount w swoim kodzie after_update.
źródło
Po pierwsze, powinieneś to zrobić w transakcji, aby upewnić się, że Twoje dane zostaną zapisane razem.
Aby odpowiedzieć na twoje pytanie, możesz po prostu ustawić zmienną składową na starą wartość w before_update, do której możesz uzyskać dostęp w after_update, jednak nie jest to zbyt eleganckie rozwiązanie.
źródło
Pomysł 1: Zapakuj aktualizację w transakcję bazy danych, aby w przypadku niepowodzenia aktualizacji tabela Totals nie uległa zmianie: Dokumentacja transakcji ActiveRecord
Pomysł 2: Zachowaj starą wartość w @old_total podczas przed_aktualizacją.
źródło
Jeśli chcesz uzyskać wartość danego pola po aktualizacji możesz skorzystać z metody field_before_last_save.
Example: u = User.last u.update(name: "abc") u.name_before_last_save will give you old value (before update value)
źródło