Rails 3 проверяет, изменился ли атрибут

153

Необходимо проверить, изменился ли блок атрибутов перед обновлением в Rails 3.

улица1, улица2, город, штат, почтовый индекс

Я знаю, что мог бы использовать что-то вроде

if @user.street1 != params[:user][:street1]
  then do something....
end

Но этот кусок кода будет очень долго. Есть ли более чистый способ?

pcasa
источник

Ответы:

282

Проверьте ActiveModel :: Dirty (доступно по умолчанию на всех моделях). Документация действительно хорошая, но она позволяет вам делать такие вещи, как:

@user.street1_changed? # => true/false
Питер Браун
источник
Это не поможет, если вы пытаетесь увидеть, был ли атрибут изменен в форме (что, по-видимому, и делает OP).
Марк Фрейзер
8
Конечно, это так. Если вы присваиваете значения с помощью хэша params, они приходят из формы.
Питер Браун
что если я захочу сделать что-то вроде этого: model.collection.changed_size_by? или что-то вроде
Мауро Диас
@MauroDias вы должны написать свою собственную логику для отслеживания свойств коллекции, как это.
Питер Браун
Я попытаюсь использовать тестовую библиотеку для этого. В любом случае, это может быть обходной путь TY
Мауро Диас
54

Так я решил проблему проверки изменений в нескольких атрибутах.

attrs = ["street1", "street2", "city", "state", "zipcode"]

if (@user.changed & attrs).any?
  then do something....
end

changedМетод возвращает массив атрибутов измененных для этого объекта.

Оба @user.changedи attrsявляются массивами, поэтому я могу получить пересечение (см. ary & other aryМетод). Результатом пересечения является массив. Вызывая any?массив, я получаю истину, если есть хотя бы одно пересечение.

Также очень полезно, changed_attributesметод возвращает хэш атрибутов с их исходными значениями иchanges возвращает хэш атрибутов с их исходными и новыми значениями (в массиве).

Вы можете проверить APIDock, для каких версий поддерживаются эти методы.

http://apidock.com/rails/ActiveModel/Dirty

campeterson
источник
1
Это хороший способ сделать это. Исторически я сделалif attrs.any?{|attr| @user.send("#{attr}_changed?")} Когда я хочу проверить, не изменился ли один из нескольких различных атрибутов - конечно, я делаю это только с теми атрибутами, которые я определил сам, потому что я не люблю бросать пользовательские параметры в sendметод. ;)
nzifnab
14

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

Если вы пытаетесь обнаружить много изменений атрибутов, это может привести к путанице. Вероятно, не следует делать это в контроллере, но ме.

hamstar
источник
9
Для чего это стоит, вы можете сделать это, previous_changesчто также доступно по умолчанию.
Джейсон Галутен
2
#update_attributesне скрывает изменения Сохраняет запись, поэтому модель обновляется и изменений нет. Вам нужно изменить поле в модели и проверить его changed?перед сохранением. то есть. @ model.field = 'foo' или@model.attributes = @model.attributes.merge(params[:model])
Гжегож
9

Для рельсов 5.1+ обратные вызовы

Начиная с Ruby on Rails 5.1, методы attribute_changed?и attribute_wasActiveRecord устарели

Используйте saved_change_to_attribute?вместоattribute_changed?

@user.saved_change_to_street1? # => true/false

Больше примеров здесь

Лукас Андраде
источник
2

Приведенные выше ответы лучше, но, тем не менее, для понимания у нас есть и другой подход: давайте изменили значение столбца 'catagory' для объекта (@design),

@design.changes.has_key?('catagory')

.Changes вернет хеш с ключом в качестве имени столбца и значения в виде массива с двумя значениями [old_value, new_value] для каждого столбца. Например, категория выше была изменена с «ABC» на «XYZ» в @design,

@design.changes   # => {} 
@design.catagory = 'XYZ'
@design.changes # => { 'catagory' => ['ABC', 'XYZ'] }

Для смены ссылок в ROR

шубхам мишра
источник