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

更新单个属性并保存记录,而无需执行正常的验证过程。这对于现有记录上的布尔标志特别有用。混入验证模块时,Base中的常规update_attribute方法将替换为该方法,默认情况下为默认方法。

用于update_attributes

从传入的哈希中更新所有属性并保存记录。如果对象无效,则保存将失败并且将返回false。

因此,如果我不想验证对象,则应使用update_attribute。如果我在before_save上进行了更新,将会导致stackoverflow吗?

我的问题是,update_attribute是否也绕过了之前的保存或只是验证。

另外,将哈希传递给update_attributes的正确语法是什么...在顶部查看我的示例。


为什么要update_attributebefore_save回调中放入一条语句?我想不到一个很好的理由。
丹尼尔·皮兹奇

1
我有一些需要根据更新后的对象数量进行更新的对象。有什么更好的办法?
thenengah

我是对的,您需要更新的对象是您要保存的对象的属性吗?如果是,那么您只需设置它们,它们就会随已保存的对象一起更新(因为它们是在before_save回调中设置的)。铁代替update_attribute(:discount, 0.1) if amount > 100你可以做discount = 0.1 if amount > 100update_attribute调用save对象,在这种情况下是不必要的,因为该语句位于before_save回调内部,并且无论如何都会被保存。我希望这是有道理的。
丹尼尔·皮茨奇

是的,没有。但是,您引用的对象的状态取决于保存之前无法处理的其他条件。
thenengah

3
请注意,这些方法会跳过验证,但仍会执行回调,例如after_save ...
rogerdpack 2013年

Answers:


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_validation为,则绕过(跳过将是正确的词)与关联的所有验证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所说的话
Raf

3
@Batkins仍然没有运行验证-这是最重要的部分:)
Tigraine

1
至少从Rails 5.1开始,以上链接不再准确。这些方法已移至ActiveRecord :: Persistence。您可以在此处找到更新的信息:update属性update_attributes注意:update_attributes现在是update
tgf '18

74

提示: update_attribute在Rails 4中,通过Commit a7f4b0a1不推荐使用。它消除了update_attribute对的支持update_column


45
这不再是事实;该方法已被重新添加。见github.com/rails/rails/pull/6738#issuecomment-39584005
丹尼斯

20
update_attribute跳过验证,但尊重回调,update_column将跳过验证和回调,并且不会更新:updated_at,这update是将同时尊重回调和验证的正常功能
Mohammad AbuShady 2014年

2
他们会已经下定决心吗?reset_column,update_column也已弃用。
ahnbizcad 2014年

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/。例如,它在运行验证,触摸对象的updated_at或触发回调等方面有所不同。

作为OP问题的答案,请update_attribute不要通过回调。


是的,我修改了答案。感谢您的反馈。
adamliesko

4

update_attributeupdate_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_saveetc之类的任何其他回调。因此,如果您确实想“仅更新列并跳过任何AR任务”,则需要使用(显然)

Model.update_all(...)参见https://stackoverflow.com/a/7243777/32453


2

最近我遇到了update_attributevs。update_attributes和验证问题,所以名称相似,行为不同,令人困惑。

为了将哈希传递给update_attribute并绕过验证,您可以执行以下操作:

object = Object.new
object.attributes = {
  field1: 'value',
  field2: 'value2',
  field3: 'value3'
}
object.save!(validate: false)

1

我认为您的问题是,在before_save中包含update_attribute是否会导致无限循环(之前由update_attribute调用触发的before_save回调中的update_attribute调用)

我很确定它确实绕过了before_save回调,因为它实际上并没有保存记录。您还可以通过使用保存记录而不触发验证

Model.save false

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.