407

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',但我想在一行上更新它们。

4

4 回答 4

635

我相信您正在寻找的是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
于 2012-08-02T17:54:08.230 回答
197

您可以使用assign_attributesor attributes=(它们是相同的)

更新方法备忘单(适用于 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

于 2013-09-12T11:31:52.807 回答
66

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

@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 为真(默认值),则可以使用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
于 2011-07-21T02:25:14.127 回答
9

对于在不保存的情况下将值批量分配给 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_attributes与Rails 3 略有不同。attributes=将检查传递给它的参数是否为 Hash,如果不是则立即返回;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[]了最终的结果.map。保留上面 50 行的一些代码,并从属性分配中删除 3 个函数,你就有了失败的秘诀。

Rails 3 的教训是:始终使用assign_attributes而不是attributes=.

导轨 4

在 Rails 4 中,attributes=只是assign_attributes. 请参阅ActiveRecord 属性分配 API 文档以获取attributes=.

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

验证

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

valid?可以这样使用:

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

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

于 2016-05-17T15:16:01.740 回答