#ruby-on-rails #callback
#ruby-on-rails #обратный вызов
Вопрос:
В моем приложении у меня есть следующая ассоциация:
# Page
belongs_to :status
Я хочу запускать обратный вызов в любое status_id
время, когда значение a page
изменилось.
Итак, если page.status_id
идет от 4 до 5, я хочу иметь возможность это перехватить.
Как это сделать?
Ответ №1:
Rails 5.1
class Page < ActiveRecord::Base
before_save :do_something, if: :will_save_change_to_status_id?
private
def do_something
# ...
end
end
Коммит, который изменил ActiveRecord::Dirty, находится здесь: https://github.com/rails/rails/commit/16ae3db5a5c6a08383b974ae6c96faac5b4a3c81
Вот сообщение в блоге об этих изменениях: https://www.fastruby.io/blog/rails/upgrades/active-record-5-1-api-changes
Вот краткое изложение, которое я сделал для себя по изменениям в ActiveRecord::Dirty в Rails 5.1 :
ActiveRecord::Dirty
https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html
Перед сохранением (НЕОБЯЗАТЕЛЬНОЕ ИЗМЕНЕНИЕ)
После изменения объекта и перед сохранением в базе данных или в before_save
фильтре:
changes
теперь должно бытьchanges_to_save
changed?
теперь должно бытьhas_changes_to_save?
changed
теперь должно бытьchanged_attribute_names_to_save
<attribute>_change
теперь должно быть<attribute>_change_to_be_saved
<attribute>_changed?
теперь должно бытьwill_save_change_to_<attribute>?
<attribute>_was
теперь должно быть<attribute>_in_database
После сохранения (ПРЕРЫВАНИЕ ИЗМЕНЕНИЯ)
После изменения объекта и после сохранения в базе данных или в after_save
фильтре:
saved_changes
(заменяетprevious_changes
)saved_changes?
saved_change_to_<attribute>
saved_change_to_<attribute>?
<attribute>_before_last_save
Rails <= 5.0
class Page < ActiveRecord::Base
before_save :do_something, if: :status_id_changed?
private
def do_something
# ...
end
end
При этом используется тот факт, что before_save
обратный вызов может выполняться условно на основе возвращаемого значения вызова метода. status_id_changed?
Метод исходит из ActiveModel::Dirty , который позволяет нам проверить, изменился ли конкретный атрибут, просто добавив _changed?
к имени атрибута.
Когда do_something
следует вызывать метод, зависит от ваших потребностей. Это может быть before_save
или after_save
или любой из определенных ActiveRecord::Обратные вызовы.
Ответ №2:
В attribute_changed?
Rails 5.1 он устарел, теперь просто используйте will_save_change_to_attribute?
.
Для получения дополнительной информации см. Эту проблему.
Ответ №3:
Попробуйте это
after_validation :do_something, if: ->(obj){ obj.status_id.present? and obj.status_id_changed? }
def do_something
# your code
end