Określić, jakie atrybuty zostały zmienione w Rails po wywołaniu zwrotnym save?
Konfiguruję wywołanie zwrotne after_save w moim obserwatorze modelu, aby wysłać powiadomienie tylko wtedy, gdy atrybut published modelu został zmieniony z false na true. Od kiedy zmieniły się metody takie jak ? są przydatne tylko przed zapisaniem modelu, sposób, w jaki obecnie (i bezskutecznie) próbuję to zrobić, wygląda następująco:
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
Czy ktoś ma jakieś sugestie co do najlepszego sposobu radzenia sobie z tym, najlepiej używając wywołań zwrotnych model observer (aby nie zanieczyszczać mojego kontrolera kod)?
8 answers
W Twoim filtrze after_update
na modelu możesz użyć accessor (przynajmniej w Rails 3, nie jestem pewien Dla Rails 2). Tak na przykład:
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
To po prostu działa.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-05 08:09:06
Dla tych, którzy chcą poznać zmiany po zapisaniu, należy użyć
model.previous_changes
To działa jak model.change
, ale działa nadal po model.save
, itp.
Znalazłem to informacje przydatne, więc może ty też.
W Rails 5.1 + jest to przestarzałe. Zamiast tego użyj saved_changes
w wywołaniach zwrotnych after_save
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-18 09:47:55
W przypadku, gdy możesz to zrobić na before_save
zamiast after_save
, będziesz mógł użyć tego:
self.changed
Zwraca tablicę wszystkich zmienionych kolumn w tym rekordzie.
Możesz również użyć:
self.changes
Który zwraca hash kolumn, które uległy zmianie oraz przed i po wynikach jako tablice
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-04 12:59:51
Do każdego, kto zobaczy to później, jak to obecnie (sierpień. 2017) tops google: warto wspomnieć, że to zachowanie zostanie zmienione w Rails 5.2 i ma ostrzeżenia o deprecacji od Rails 5.1, ponieważ ActiveModel::Dirty nieco się zmieniło.
Co mam zmienić?
Jeśli używasz metody attribute_changed?
w wywołaniu after_*
-zobaczysz ostrzeżenie takie jak:
Ostrzeżenie o DEPRECACJI: zachowanie
attribute_changed?
wewnątrz wywołania po będzie zmiana w następnej wersji Rails. Nowa wartość zwracana będzie odzwierciedlać zachowanie wywołania metody po zwróceniusave
(np. odwrotność tego, co zwraca teraz). Aby zachować bieżące zachowanie, użyjsaved_change_to_attribute?
. (wywołane z some_callback w /PATH_TO / app / models / user.rb: 15)
Jak wspomniano, można to łatwo naprawić, zastępując funkcję saved_change_to_attribute?
. Na przykład name_changed?
staje się saved_change_to_name?
.
Podobnie, jeśli używasz attribute_change
, aby uzyskać przed-po wartości, to również zmienia i rzuca następujące:
Ostrzeżenie o DEPRECACJI: zachowanie
attribute_change
wewnątrz wywołań zwrotnych after zmieni się w następnej wersji Rails. Nowa wartość zwracana będzie odzwierciedlać zachowanie wywołania metody po zwróceniusave
(np. odwrotność tego, co zwraca teraz). Aby zachować bieżące zachowanie, użyjsaved_change_to_attribute
. (wywołane z some_callback w /PATH_TO / app / models / user.rb: 20)
Ponownie, jak wspomina, metoda zmienia nazwę na saved_change_to_attribute
, która zwraca ["old", "new"]
.
lub użyć saved_changes
, który zwraca wszystkie zmiany, a te mogą być dostępne jako saved_changes['attribute']
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-03 19:45:24
"wybrana" odpowiedź nie zadziałała dla mnie. Używam rails 3.1 z Couchrest:: Model (oparty na Active Model). Metody _changed?
nie zwracają true dla zmienionych atrybutów w hooku after_update
, tylko w hooku before_update
. Udało mi się go uruchomić za pomocą (nowego?) around_update
hook:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-10 19:53:32
Możesz dodać warunek do after_update
w następujący sposób:
class SomeModel < ActiveRecord::Base
after_update :send_notification, if: :published_changed?
...
end
Nie ma potrzeby dodawania warunku w samej metodzie send_notification
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-15 18:18:23
Używam tego do wyodrębniania hasha z nowymi wartościami atrybutów, co jest dla mnie przydatne do aktualizacji innych modeli
attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash}
The
attr[1].last == false
Jest potrzebne, gdy nową wartością jest false
, gdzie przypisanie zwraca false i nie zwraca" hash".
Myślę, że jest łatwiejszy sposób, jestem nowy w rails
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 14:59:55
Wystarczy dodać accesora, który określa co zmieniasz
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-05 08:08:29