Chciałbym utworzyć funkcję zwrotną w railsach, która jest wykonywana po zapisaniu modelu.
Mam ten model, Claim, który ma atrybut „status”, który zmienia się w zależności od stanu roszczenia, możliwe wartości oczekują, zatwierdzone, zatwierdzone, odrzucone
Baza danych ma „stan” z domyślną wartością „oczekująca”.
Chciałbym wykonać określone zadania po utworzeniu modelu po raz pierwszy lub zaktualizowaniu go z jednego stanu do drugiego, w zależności od tego, z jakiego stanu się zmienia.
Mój pomysł to mieć funkcję w modelu:
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
Moje pytanie brzmi: jak sprawdzić poprzednią wartość przed zmianą w modelu?
ruby-on-rails
David C.
źródło
źródło
dirty
wywołania działają wafter_save
(zarówno w Railsach 2.3, jak i 3.x). Użyłem go kilka razy.after_commit
wywołaniach zwrotnych wprowadzonych w Railsach 3.x. Na pewno się sprawdząafter_save
.after_save
jest to wywołanie zwrotne dla stanu międzyafter DML
abefore_commit
. Możesz zakończyć całą transakcjęafter_save
, rzucając wyjątek. Jeśli chcesz coś zrobić po zapisaniu bez wpływu na bieżącą operację, użyjafter_commit
:-)możesz tego użyć
self.changed
zwraca tablicę wszystkich kolumn, które uległy zmianie w tym rekordzie
możesz także użyć
self.changes
która zwraca jako tablice skrót kolumn, które uległy zmianie oraz wyniki przed i po
źródło
self.
na nich - możesz po prostu powiedziećchanged
ichanges
.self
gdy jesteś w samym modelu, ale możesz je wywołać na dowolnym obiekcie za pomocąobject.changed
iobject.changes
. :)Polecam przyjrzeć się jednej z dostępnych wtyczek automatu stanów:
Każdy z nich pozwoli ci ustawić stany i przejścia między stanami. Bardzo przydatny i łatwy sposób obsługi Twoich wymagań.
źródło
W przypadku Railsów 5.1+ powinieneś używać metody atrybutu aktywnego rekordu: save_change_to_attribute?
Więc twój model będzie wyglądał tak, jeśli chcesz wywołać jakąś metodę opartą na zmianie wartości atrybutu:
class Claim < ApplicationRecord after_save :do_this, if: Proc.new { saved_change_to_status?(from: nil, to: 'pending') } after_save :do_that, if: Proc.new { saved_change_to_status?(from: 'pending', to: 'approved') } def do_this .. .. end def do_that .. .. end end
A jeśli nie chcesz sprawdzać zmiany wartości w wywołaniu zwrotnym, możesz wykonać następujące czynności:
class Claim < ApplicationRecord after_save: :do_this, if: saved_change_to_status? def do_this .. .. end end
źródło
Widziałem, jak pytanie pojawia się w wielu miejscach, więc napisałem dla niego mały rubygem, aby kod był trochę ładniejszy (i uniknął miliona stwierdzeń if / else wszędzie): https://github.com/ronna-s / on_change . Mam nadzieję że to pomogło.
źródło
Znacznie lepiej będzie, jeśli użyjesz dobrze przetestowanego rozwiązania, takiego jak gem state_machine .
źródło