Ответ 1
Откажитесь от ActiveModel:: Dirty (доступно по умолчанию для всех моделей). Документация действительно хорошая, но она позволяет вам делать такие вещи, как:
@user.street1_changed? # => true/false
Необходимо проверить, изменился ли блок атрибутов перед обновлением в Rails 3.
street1, street2, city, state, zipcode
Я знаю, что могу использовать что-то вроде
if @user.street1 != params[:user][:street1]
then do something....
end
Но эта часть кода будет ДЕЙСТВИТЕЛЬНО длинной. Есть ли более чистый способ?
Откажитесь от ActiveModel:: Dirty (доступно по умолчанию для всех моделей). Документация действительно хорошая, но она позволяет вам делать такие вещи, как:
@user.street1_changed? # => true/false
Вот как я решил проблему проверки изменений в нескольких атрибутах.
attrs = ["street1", "street2", "city", "state", "zipcode"]
if (@user.changed & attrs).any?
then do something....
end
Метод changed
возвращает массив атрибутов, измененных для этого объекта.
Оба @user.changed
и attrs
являются массивами, поэтому я могу получить пересечение (см. метод ary & other ary
). Результатом пересечения является массив. Вызывая any?
в массиве, я получаю true, если есть хотя бы одно пересечение.
Также очень полезно, метод changed_attributes
возвращает хэш атрибутов с их исходными значениями и changes
возвращает хэш атрибутов с их исходными и новыми значениями (в массиве).
Вы можете проверить APIDock, какие версии поддерживали эти методы.
ActiveModel::Dirty
не работал у меня, потому что @model.update_attributes()
спрятал изменения. Так вот как я обнаружил изменения в методе update
в контроллере:
def update
@model = Model.find(params[:id])
detect_changes
if @model.update_attributes(params[:model])
do_stuff if attr_changed?
end
end
private
def detect_changes
@changed = []
@changed << :attr if @model.attr != params[:model][:attr]
end
def attr_changed?
@changed.include :attr
end
Если вы пытаетесь обнаружить множество изменений атрибутов, это может стать беспорядочным. Вероятно, не следует делать это в контроллере, но meh.