ChatGPT解决这个技术问题 Extra ChatGPT

Rails:#update_attribute 与 #update_attributes

obj.update_attribute(:only_one_field, 'Some Value')
obj.update_attributes(field1: 'value', field2: 'value2', field3: 'value3')

这两个都将更新一个对象,而无需明确告诉 ActiveRecord 进行更新。

Rails API 说:

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

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

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

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

此外,将散列传递给 #update_attributes 的正确语法是什么……查看我在顶部的示例。

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

A
Andre Figueiredo

请参阅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 版本中不再相关。
M
Matt

提示: update_attribute 通过 Commit a7f4b0a1 在 Rails 4 中被弃用。它删除 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 已被删除。
B
BoltClock

更新属性

此方法在不调用基于模型的验证的情况下更新对象的单个属性。

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

更新属性

此方法更新单个对象的多个属性并通过基于模型的验证。

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

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


K
Kibet Yegon

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


A
Arslan Ali

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

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


很好解释。谢谢!
a
adamliesko

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

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


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

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

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

A
AkaZecik

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_attribute(:column_name, column_value) 的位置使用 Model.update_column(:column_name, column_value)

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


r
rogerdpack

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

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


W
Wojciech Bednarski

最近我遇到了 update_attribute vs. update_attributes 和验证问题,名称如此相似,行为如此不同,如此混乱。

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

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

c
concept47

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

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

模型.save false