Определите, какие атрибуты были изменены в Rails After_save Callback?
-
27-09-2019 - |
Вопрос
Я устанавливаю обратный вызов после_save в моем модели наблюдателя, чтобы отправить уведомление только в том случае, если модель Опубликовано атрибут был изменен с false to true. Поскольку методы, такие как измененный? Потреблять только до того, как модель сохранена, то, как я сейчас (и безуспешно), пытаясь сделать это выглядит следующим образом:
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
У кого-нибудь есть какие-либо предложения относительно наилучшего способа справиться с этим, предпочтительно, используя обратные вызовы моделей наблюдателя (чтобы не загрязнять мой код контроллера)?
Решение
В твоем after_update
Фильтр на модели вы могу использовать _changed?
Accessor (хотя бы в рельсах 3, не уверен для рельсов 2). Так, например:
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
Это просто работает.
Другие советы
Для тех, кто хочет знать изменения, только что сделанные в after_save
Перезвоните:
Рельсы 5.1 и больше
model.saved_changes
Рельсы <5.1
model.previous_changes
Также см: http://api.rubyonrails.org/Classes/activeModel/dirty.html#method-deprevious_changes.
Кто-нибудь увидеть это позже, так как в настоящее время он в настоящее время (августа 2017) топы Google: стоит упомянуть, что это поведение будет изменено в Рельсы 5.2, и имеет обесценение предупреждений с рельсами 5.1, как ActiveModel :: грязно изменился немного.
Что я могу изменить?
Если вы используете attribute_changed?
метод в after_*
-Callbacks, вы увидите предупреждение, как:
Предупреждение о снижении: поведение
attribute_changed?
Внутри после обратных вызовов будут меняться в следующей версии рельсов. Новое возвращаемое значение будет отражать поведение вызывающего метода послеsave
Вернулся (например, противоположность того, что он возвращается сейчас). Поддерживать текущее поведение, используйтеsaved_change_to_attribute?
вместо. (называется из quey_callback на /path_to/app/models/user.rb:15)
Как упоминается, вы можете легко исправить это, заменив функцию с saved_change_to_attribute?
. Отказ Так, например, name_changed?
становится saved_change_to_name?
.
Аналогично, если вы используете attribute_change
Чтобы получить ранее после ценностей, это меняется, а также бросает следующее:
Предупреждение о снижении: поведение
attribute_change
Внутри после обратных вызовов будут меняться в следующей версии рельсов. Новое возвращаемое значение будет отражать поведение вызывающего метода послеsave
Вернулся (например, противоположность того, что он возвращается сейчас). Поддерживать текущее поведение, используйтеsaved_change_to_attribute
вместо. (называется из quey_callback на /path_to/app/models/user.rb:20)
Опять же, как упоминается, метод меняет имя saved_change_to_attribute
который возвращает ["old", "new"]
Отказ или использовать saved_changes
, который возвращает все изменения, и их можно получить доступ как saved_changes['attribute']
.
Если вы можете сделать это на before_save
вместо after_save
, Вы сможете использовать это:
self.changed
Он возвращает массив всех измененных столбцов в этой записи.
Вы также можете использовать:
self.changes
который возвращает хеш столбцов, изменившихся и до и после результатов в качестве массивов
«Выбранный» ответ не работал для меня. Я использую Rails 3.1 с Couchrest :: Модель (на основе активной модели). То _changed?
Методы не возвращаются для измененных атрибутов в after_update
крючок, только в before_update
крюк. Я смог заставить его работать, используя (New?) around_update
крюк:
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
Вы можете добавить условие в after_update
вот так:
class SomeModel < ActiveRecord::Base
after_update :send_notification, if: :published_changed?
...
end
Нет необходимости добавлять условие в send_notification
сам метод.
Я использую это, чтобы извлечь хеш с новыми значениями атрибута, что полезно для меня, чтобы обновить другие модели
attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash}
То
attr[1].last == false
нужен, когда новое значение false
, где назначение возвращает false и "hash" не возвращается.
Я думаю, что есть проще, я новичок в рельсы
Вы просто добавляете аксес, который определяет то, что вы меняете
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