Rails:#update_attribute 与 #update_attributes

Posted

技术标签:

【中文标题】Rails:#update_attribute 与 #update_attributes【英文标题】:Rails: #update_attribute vs #update_attributes 【发布时间】:2011-02-16 05:41:10 【问题描述】:
obj.update_attribute(:only_one_field, 'Some Value')
obj.update_attributes(field1: 'value', field2: 'value2', field3: 'value3')

这两种方法都会更新对象,而无需明确告诉 ActiveRecord 进行更新。

Rails API 说:

更新属性

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

更新属性

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

所以如果我不想验证对象,我应该使用#update_attribute。如果我在#before_save 上有这个更新,它会溢出吗?

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

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

【问题讨论】:

为什么要将update_attribute 语句放在before_save 回调中?我想不出一个很好的理由。 我有需要根据更新对象的数量进行更新的对象。有什么更好的方法? 我是对的,您需要更新的对象是您正在保存的对象的属性吗?如果是,那么您可以设置它们,它们将与无论如何保存的对象一起更新(因为它们是在before_save 回调中设置的)。 F.e.而不是update_attribute(:discount, 0.1) if amount > 100,你可以做discount = 0.1 if amount > 100update_attribute 在对象上调用 save,在这种情况下这是不必要的,因为该语句在 before_save 回调中并且无论如何都会被保存。我希望这是有道理的。 是和不是。但是,您所指的对象的状态取决于保存前无法处理的其他条件。 请注意,这些方法会跳过验证,但会仍然执行回调,例如 after_save ... 【参考方案1】:

请参考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 关联的所有validations。

第二个问题

另外,将哈希传递给 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])

【讨论】:

您关于回调的说法不正确,至少在Rails 3 中是不正确的。它在the comments in the source 中非常明确地说“调用了回调”。 我赞同@Batkins 所说的 @Batkins 仍然没有运行验证 - 这是最重要的部分 :) 以上链接至少在 Rails 5.1 中不再准确。这些方法已移至 ActiveRecord::Persistence。你可以在这里找到更新的信息:update attribute 和这里 update_attributes 注意:update_attributes 现在是 update 的别名 这个答案已经过时了——链接已经失效,引用的源代码在最近的 ActiveRecord 版本中不再相关。【参考方案2】:

我认为您的问题是,如果在 before_save 中有 update_attribute 会导致无限循环(在 before_save 回调中调用 update_attribute,最初由 update_attribute 调用触发)

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

保存记录而不触发验证

Model.save false

【讨论】:

【参考方案3】:

提示: update_attribute 在 Rails 4 中被 Commit a7f4b0a1 弃用。它删除了update_attribute 以支持update_column

【讨论】:

这不再是真的;该方法已重新添加。见github.com/rails/rails/pull/6738#issuecomment-39584005 update_attribute 跳过验证,但尊重回调,update_column 将跳过验证和回调并且不会更新 :updated_atupdate 是尊重回调和验证的正常函数跨度> 他们是否已经下定决心了。不推荐使用 reset_column、update_column。 update_column 未被弃用,但update_columns(name: value) 受到青睐。 reset_column 已被删除。【参考方案4】:

另外值得注意的是,对于update_attribute,要更新的所需属性不需要与attr_accessible 一起被列入白名单来更新它,而批量分配方法update_attributes 只会更新@987654324 @指定属性。

【讨论】:

【参考方案5】:

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)

希望这个答案能明确何时使用什么方法进行活动记录。

【讨论】:

【参考方案6】:

update_attributeupdate_attributes 相似,但 有一个很大的区别:update_attribute 运行验证。

还有:

update_attribute 用于更新具有 single 属性的记录。

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)

Click here 获取有关update_column 的更多信息。

【讨论】:

【参考方案7】:

要回答您的问题,update_attribute 会跳过预保存“验证”,但它仍会运行任何其他回调,例如 after_save 等。因此,如果您真的想“只需更新列并跳过任何 AR cruft" 那么你需要使用(显然)

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

【讨论】:

【参考方案8】:

很好的答案。 请注意,对于 ruby​​ 1.9 及更高版本,您可以(我认为应该)为 update_attributes 使用新的哈希语法:

Model.update_attributes(column1: "data", column2: "data")

【讨论】:

【参考方案9】:

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

如果验证失败,它不会更新。

【讨论】:

解释得很好。谢谢!【参考方案10】:

最近我遇到了update_attributeupdate_attributes 的验证问题,名称如此相似,行为如此不同,如此混乱。

为了将哈希传递给update_attribute 并绕过验证,您可以这样做:

object = Object.new
object.attributes = 
  field1: 'value',
  field2: 'value2',
  field3: 'value3'

object.save!(validate: false)

【讨论】:

【参考方案11】:

您可能有兴趣访问此博客文章,了解所有可能的分配属性或更新记录的方法(更新到 Rails 4)update_attribute, update, update_column, update_columns etc.http://www.davidverhasselt.com/set-attributes-in-activerecord/。例如,它在运行验证、触摸对象的 updated_at 或触发回调等方面有所不同。

作为对 OP 问题的回答 update_attribute 不会通过回调。

【讨论】:

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

以上是关于Rails:#update_attribute 与 #update_attributes的主要内容,如果未能解决你的问题,请参考以下文章

为啥 update_attributes 会破坏我的 Rails 应用程序?

Rails form_with(remote:true)错误

如何在 Ruby on Rails 应用程序中处理 RESTful URL 参数?

ruby update_attribute.rb

更改通知消息取决于更新的属性

PhoneGap 和 rails 3:如何与 rails 3 应用程序交互