Rails: update_attribute vs update_attributes


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

Обидва вони будуть оновлювати об'єкт, не вимагаючи явного вказівки AR для оновлення.

API Rails говорить:

для update_attribute

Оновляється один атрибут і зберігається запис, не проходячи звичайну процедуру перевірки. Це особливо корисно для булевих прапорів на існуючих записах. Метод регулярного update_attribute в Base замінюється цим, коли змішується модуль перевірки, який є за замовчуванням.

для update_attributes

Оновляє всі атрибути з переданого Hash і зберігає запис. Якщо об'єкт недійсний, збереження не вдасться, а помилка повернеться.

Тож якщо я не хочу перевіряти об'єкт, я повинен використовувати update_attribute. Що робити, якщо у мене є це оновлення на файлі before_save, чи воно буде stackoverflow?

Моє запитання полягає в тому, чи update_attribute також обходить попереднє збереження або просто перевірку.

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


Чому ви хочете помістити update_attributeзаяву всередину before_saveзворотного дзвінка? Я не можу придумати для цього вагомих причин.
Даніель Піцш

1
У мене є об’єкти, які потрібно оновити, виходячи із суми оновленого об’єкта. Який кращий спосіб?
thenengah

Я правий, що об’єкти, які потрібно оновити, є атрибутами об'єкта, який ви зберігаєте? Якщо так, то ви можете просто встановити їх, і вони будуть оновлені разом із об'єктом, який все одно збережено (тому що вони встановлені в межах before_saveзворотного дзвінка). Фе замість update_attribute(:discount, 0.1) if amount > 100вас міг зробити discount = 0.1 if amount > 100. update_attributeвикликає saveоб'єкт, що в цьому випадку непотрібне, оскільки оператор знаходиться всередині before_saveзворотного дзвінка і все одно буде збережений. Сподіваюся, це має сенс.
Даніель Піцш

Так і ні. Однак стан об'єктів, на які ви посилаєтесь, залежить від інших умов, які неможливо обробити перед збереженням.
thenengah

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])

7
Твоє твердження про зворотні дзвінки є невірним, принаймні в Rails 3. У коментарях у джерелі це чітко сказано, що "Виклики викликаються".
Баткінс

Я другий, що говорить @Batkins
Раф

3
@Batkins досі не перевіряється - це найважливіша частина :)
Tigraine

1
Посилання, наведені вище, вже не є точними, щонайменше, як для Rails 5.1 . Ці методи були переміщені до ActiveRecord :: Наполегливість. Ви можете знайти оновлену інформацію тут: атрибут update та тут update_attributes Примітка: update_attributesтепер псевдонім дляupdate
tgf

74

Порада: update_attribute застаріла в Рейки 4 через Комітет a7f4b0a1 . Це знімає update_attributeна користь update_column.


45
Це вже не відповідає дійсності; метод був повторно доданий. Дивіться github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis

20
update_attributeскаче перевірки, але поважає зворотні виклики, update_columnпропустять як перевірку і зворотні виклики , а також не відновлення :updated_at, updateце нормальна функція , яка буде поважати як зворотні виклики і перевірки
Мохаммад AbuShady

2
чи вони вже складуть свою думку reset_column, також застарілий update_column.
ahnbizcad

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)

Сподіваюся, що ця відповідь дозволить зрозуміти, коли використовувати який метод активного запису.


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/ . Наприклад, він відрізняється в таких аспектах, як запуск перевірок, торкання оновленого_об'єкта або запуск зворотних викликів.

Як відповідь на питання ОП update_attributeне проходять зворотні дзвінки.


Так, я змінив відповідь. Дякуємо за відгук.
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-крафт", тоді вам потрібно скористатися (очевидно)

Model.update_all(...)див. https://stackoverflow.com/a/7243777/32453


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 в режимі "передумови" призведе до нескінченного циклу (виклики оновлення_атехніки в зворотних викликах раніше_сав, спочатку викликані викликом update_attribute)

Я впевнений, що він обходить зворотний виклик перед_save, оскільки він фактично не зберігає запис. Ви також можете зберегти запис, не запускаючи перевірки, використовуючи

Model.save false

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.