Rails update_attributes没有保存?


385

有没有替代update_attributes而不保存记录的方法?

所以我可以做类似的事情:

@car = Car.new(:make => 'GMC')
#other processing
@car.update_attributes(:model => 'Sierra', :year => "2012", :looks => "Super Sexy, wanna make love to it")
#other processing
@car.save

顺便说一句,我知道我可以@car.model = 'Sierra',但是我想一次全部更新它们。


您是什么意思“不保存记录”?
阿纳托利

update_attributes将模型保存到数据库中。我想知道是否有类似的方法没有。
tybro0103

3
属性无损方法。有关详细信息,请参见API
Anatoly

3
您可以使用update_column(name,value)更新对象的单个属性,而无需调用save。1.跳过验证。2.跳过回调。3.如果该列可用,则updatedat / updated_on列不会更新。apidock.com/rails/ActiveRecord/Persistence/update_column
Antoine

10
对于3.1+,请使用assign_attributes apidock.com/rails/ActiveRecord/Base/assign_attributes
Elado 2012年

Answers:


596

我相信您正在寻找的是assign_attributes

它与update_attributes基本相同,但不保存记录:

class User < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :name, :is_admin, :as => :admin
end

user = User.new
user.assign_attributes({ :name => 'Josh', :is_admin => true }) # Raises an ActiveModel::MassAssignmentSecurity::Error
user.assign_attributes({ :name => 'Bob'})
user.name        # => "Bob"
user.is_admin?   # => false
user.new_record? # => true

您的示例有点误导,因为您还没有从模型中粘贴以下行:attr_accessible :is_admin, :as => :admin;)
Robin Robin's

@Robin或简单地:attr_protected :is_admin。或:attr_accessible :name关键是在此示例中,:is_admin受保护。我还应注意,即使未在示例中显示,尝试大规模分配具有的受保护属性.assign_attributes的确会引发ActiveModel::MassAssignmentSecurity::Error
2012年

是的,但我的电话来自您链接到的文档。我只是说您应该复制/粘贴了整个示例。但是,可以的,您可以说它是受保护的。
罗宾(Robin)

@Robin我将更新示例以使其更加具体。文档中的示例也有点误导,因为它没有提到user.assign_attributes({ :name => 'Josh', :is_admin => true })引发错误消息并且实际上没有设置用户的name属性。
2012年

7
从Rails 3.1以及更高版本开始都可以使用assign_attributes,因此如果您仍在运行旧版本的Rails,则不能使用它。
海因

173

您可以使用assign_attributesattributes=(它们相同)

更新方法备忘单(适用于Rails 6):

  • update= assign_attributes+save
  • attributes= =的别名 assign_attributes
  • update_attributes =已弃用,别名为 update

来源:
https : //github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment .rb

另一个备忘单:http :
//www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet


1
清晰简短。谢谢。
Freemanoid 2014年

1
在.attributes = val的情况下,如果您的模型has_one和accepts_nested_attributes_用于另一个模型,则传递that_model_attributes(不带id)将删除现有的has_one模型,即使您没有坚持(例如保存)。但是assign_attributes的行为并非如此。
ClassyPimp

65

您可以使用“属性”方法:

@car.attributes = {:model => 'Sierra', :years => '1990', :looks => 'Sexy'}

来源:http//api.rubyonrails.org/classes/ActiveRecord/Base.html

attributes =(new_attributes,guard_protected_attributes = true) 允许您通过传入散列值与属性名称匹配的键(又与列名称匹配)来一次设置所有属性。

如果guard_protected_attributes为true(默认设置),则可以使用attr_protected宏保护敏感属性免受这种形式的大量分配。或者,您也可以指定可以使用attr_accessible宏访问哪些属性。这样一来,所有未包含在其中的属性都将无法进行大规模分配。

class User < ActiveRecord::Base
  attr_protected :is_admin
end

user = User.new
user.attributes = { :username => 'Phusion', :is_admin => true }
user.username   # => "Phusion"
user.is_admin?  # => false

user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
user.is_admin?  # => true

7

要将值批量分配给ActiveRecord模型而不保存,请使用assign_attributesattributes=方法。这些方法在Rails 3和更高版本中可用。但是,需要注意一些细微的差异以及与版本相关的陷阱。

两种方法都遵循这种用法:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }

@user.attributes = { model: "Sierra", year: "2012", looks: "Sexy" }

注意,这两种方法都不会执行验证或执行回调。回调和验证将在save被调用时发生。

导轨3

attributes=assign_attributesRails 3 略有不同。 attributes=将检查传递给它的参数是否为哈希,如果不是,则立即返回;否则返回false。assign_attributes没有这种哈希检查。请参阅ActiveRecord属性分配API文档attributes=

以下无效代码将通过仅返回而不设置属性而静默失败:

@user.attributes = [ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ]

attributes= 会默默地表现出分配已成功完成的事实,但实际上并非如此。

assign_attributes试图对封闭数组的哈希键进行字符串化时,此无效代码将引发异常:

@user.assign_attributes([ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ])

assign_attributes将引发的NoMethodError异常stringify_keys,指示第一个参数不是哈希。异常本身并不能很好地说明实际原因,但是异常确实发生的事实非常重要。

这些情况之间的唯一区别是用于批量分配的方法:attributes=默默地成功,并assign_attributes引发异常以通知已发生错误。

这些示例在一定程度上看似是人为的,但是当从API转换数据时,甚至只是使用一系列数据转换而忘Hash[]了final的结果时,都容易发生这种类型的错误.map。保持上面的50行代码和从属性分配中删除的3个功能,您将获得失败的秘诀。

Rails 3的课程是:始终使用assign_attributes代替attributes=

滑轨4

在Rails 4中,attributes=只是的别名assign_attributes。请参阅ActiveRecord属性分配API文档attributes=

对于Rails 4,这两种方法都可以互换使用。未能将哈希作为第一个参数传递将导致非常有用的异常:ArgumentError: When assigning attributes, you must pass a hash as an argument.

验证方式

如果您正在准备准备之前的飞行任务save,那么您可能也有兴趣在保存之前进行验证。您可以使用valid?invalid?方法。两者都返回布尔值。 valid?如果未保存的模型通过所有验证,则返回true;否则,返回false。 invalid?简直是valid?

valid? 可以这样使用:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid?

这将使您能够在调用之前处理任何验证问题save

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.