Rails: update_attribute против update_attributes

255
Object.update_attribute(:only_one_field, "Some Value")
Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

Оба из них обновят объект без необходимости явно указывать AR для обновления.

Rails API говорит:

для update_attribute

Обновляет отдельный атрибут и сохраняет запись, не проходя обычную процедуру проверки. Это особенно полезно для логических флагов на существующих записях. Обычный метод update_attribute в Base заменяется этим при смешивании модуля валидации, который используется по умолчанию.

для update_attributes

Обновляет все атрибуты из переданного хэша и сохраняет запись. Если объект недействителен, сохранение не удастся и будет возвращено false.

Поэтому, если я не хочу проверять объект, я должен использовать update_attribute. Что если у меня будет это обновление для before_save, будет ли это переполнение стека?

Мой вопрос, делает ли update_attribute обход перед сохранением или только проверку.

Кроме того, каков правильный синтаксис для передачи хэша в update_attributes ... посмотрите мой пример вверху.

thenengah
источник
Почему вы хотите поместить update_attributeзаявление в before_saveобратный вызов? Я не могу придумать вескую причину для этого.
Даниэль Питцш
1
У меня есть объекты, которые должны быть обновлены в зависимости от количества обновленного объекта. Какой способ лучше?
тогда
Я прав, что объекты, которые вам нужно обновить, являются атрибутами сохраняемого объекта? Если да, то вы можете просто установить их, и они будут обновляться вместе с объектом, который все равно сохраняется (потому что они установлены в before_saveобратном вызове). ИП вместо update_attribute(:discount, 0.1) if amount > 100тебя мог сделать discount = 0.1 if amount > 100. update_attributeвызывает saveобъект, который в этом случае не нужен, поскольку оператор находится внутри функции before_saveобратного вызова и все равно будет сохранен. Я надеюсь, что в этом есть смысл.
Даниэль Питцш
Да и нет. Однако состояние объектов, на которые вы ссылаетесь, зависит от других условий, которые не могут быть обработаны до сохранения.
затем
3
как примечание, эти методы пропускают проверку, но все еще будут выполнять обратные вызовы, как after_save ...
rogerdpack

Ответы:

328

Пожалуйста, обратитесь к update_attribute. При нажатии на кнопку Показать исходный код вы получите следующий код

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2614
2614:       def update_attribute(name, value)
2615:         send(name.to_s + '=', value)
2616:         save(false)
2617:       end

а теперь обратитесь update_attributesи посмотрите на его код, который вы получите

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2621
2621:       def update_attributes(attributes)
2622:         self.attributes = attributes
2623:         save
2624:       end

разница между двумя update_attributeиспользует, save(false)тогда как update_attributesиспользует saveили вы можете сказать save(true).

Извините за длинное описание, но важно то, что я хочу сказать. save(perform_validation = true)Если значение perform_validationfalse, оно обходит (пропускает правильное слово) все проверки, связанные с save.

Для второго вопроса

Кроме того, каков правильный синтаксис для передачи хэша в update_attributes ... посмотрите мой пример вверху.

Ваш пример верен.

Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

или

Object.update_attributes :field1 => "value", :field2 => "value2", :field3 => "value3"

или если вы получите все поля данных и имени в хеш-коде, params[:user]используйте здесь просто

Object.update_attributes(params[:user])
Salil
источник
7
Ваше утверждение о обратных вызовах неверно, по крайней мере, в Rails 3. В комментариях в источнике очень ясно сказано, что «обратные вызовы вызываются».
Баткинс
Я второй, что говорит @Batkins
Raf
3
@ Баткинс все еще проверки не проводятся - это самая важная часть :)
Tigraine
1
Ссылки выше не являются точными, по крайней мере, в Rails 5.1 . Эти методы были перемещены в ActiveRecord :: Persistence. Вы можете найти обновленную информацию здесь: атрибут update и здесь update_attributes Примечание: update_attributesтеперь это псевдоним дляupdate
tgf
74

Совет: update_attribute в Rails 4 не рекомендуется использовать Commit a7f4b0a1 . Удаляет update_attributeв пользу update_column.

Matt
источник
45
Это больше не правда; метод был повторно добавлен. См. Github.com/rails/rails/pull/6738#issuecomment-39584005
Деннис
20
update_attributeпропускает проверку, но учитывает обратные вызовы, update_columnпропускает как проверки, так и обратные вызовы и не будет обновлять :updated_at, updateэто нормальная функция, которая будет
учитывать
2
они уже примут решение. reset_column, update_column также не рекомендуется.
анбизкад
2
update_columnне считается устаревшим, но update_columns(name: value)является предпочтительным. reset_columnбыл удален.
onebree
15

update_attribute

Этот метод обновляет отдельный атрибут объекта, не вызывая проверку на основе модели.

obj = Model.find_by_id(params[:id])
obj.update_attribute :language, java

update_attributes

Этот метод обновляет несколько атрибутов одного объекта, а также проходит проверку на основе модели.

attributes = {:name => BalaChandar”, :age => 23}
obj = Model.find_by_id(params[:id])
obj.update_attributes(attributes)

Надеюсь, этот ответ прояснит, когда использовать какой метод активной записи.

Balachandar1887229
источник
12

Также стоит отметить, что при update_attributeобновлении требуемый атрибут не обязательно должен быть занесен в белый список, attr_accessibleв отличие от метода массового назначения, update_attributesкоторый будет обновлять только attr_accessibleуказанные атрибуты.

Кибет Йегон
источник
8

update_attributeпросто обновляет только один атрибут модели, но мы можем передать несколько атрибутов в update_attributesметод.

Пример:

user = User.last

#update_attribute
user.update_attribute(:status, "active")

Это проходит проверку

#update_attributes
user.update_attributes(first_name: 'update name', status: "active")

он не обновляется, если проверка не удалась.

Шоаиб Малик
источник
Очень хорошо объяснил. Спасибо!
Диего
6

Отличные ответы. обратите внимание, что для ruby ​​1.9 и выше вы можете (и я думаю, что следует) использовать новый синтаксис хеша для update_attributes:

Model.update_attributes(column1: "data", column2: "data")
Зив Галили
источник
6

Возможно, вас заинтересует посещение этого блога, посвященного всем возможным способам назначения атрибута или обновления записи (обновлено до Rails 4) update_attribute, update, update_column, update_columns etc. http://www.davidverhasselt.com/set-attributes-in-activerecord/ . Например, он отличается такими аспектами, как выполнение проверок, касание объекта updated_at или запуск обратных вызовов.

В качестве ответа на вопрос ОП update_attributeне проходят обратные вызовы.

adamliesko
источник
Да, конечно, я изменил ответ. Спасибо за ответ.
adamliesko
4

update_attributeи update_attributesпохожи, но с одной большой разницей: update_attribute не запускает проверки.

Также:

  • update_attributeиспользуется для обновления записи с одним атрибутом.

    Model.update_attribute(:column_name, column_value1)
  • update_attributesиспользуется для обновления записи с несколькими атрибутами.

    Model.update_attributes(:column_name1 => column_value1, :column_name2 => column_value2, ...)

Эти два метода действительно легко спутать, учитывая их сходные имена и работы. Поэтому update_attributeудаляется в пользуupdate_column .

Теперь в Rails4 вы можете использовать Model.update_column(:column_name, column_value)на местеModel.update_attribute(:column_name, column_value)

Нажмите здесь, чтобы получить больше информации о update_column.

Ума
источник
4

Чтобы ответить на ваш вопрос, update_attributeпропускайте предварительно сохраненные «проверки», но он по- прежнему запускает любые другие обратные вызовы, например, after_saveи т. Д. Поэтому, если вы действительно хотите «просто обновить столбец и пропустить любое AR-Cruft», то вам нужно использовать (очевидно)

Model.update_all(...)см. https://stackoverflow.com/a/7243777/32453

rogerdpack
источник
2

Недавно я столкнулся update_attributeс update_attributesпроблемой « против» и «проверки», такими похожими именами, таким разным поведением, таким запутанным.

Чтобы передать хеш update_attributeи обойти проверку, вы можете сделать:

object = Object.new
object.attributes = {
  field1: 'value',
  field2: 'value2',
  field3: 'value3'
}
object.save!(validate: false)
Войцех Беднарски
источник
1

Я думаю, что ваш вопрос, если наличие атрибута update_attribute в before_save приведет к бесконечному циклу (вызовов update_attribute в обратных вызовах before_save, первоначально инициированных вызовом update_attribute)

Я почти уверен, что он обходит обратный вызов before_save, так как фактически не сохраняет запись. Вы также можете сохранить запись, не вызывая проверки с помощью

Model.save false

concept47
источник