Rails update_attributes 没有保存?

Posted

技术标签:

【中文标题】Rails update_attributes 没有保存?【英文标题】:Rails update_attributes without save? 【发布时间】:2011-10-09 20:46:33 【问题描述】:

有没有不保存记录的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 将模型保存到数据库中。我想知道是否有类似的方法没有。 属性非破坏性方法。详情见API 您可以使用 update_column(name, value) 更新对象的单个属性,而无需调用 save。 1. 跳过验证。 2. 回调被跳过。 3. 如果该列可用,updated_at/updated_on 列不会更新。 apidock.com/rails/ActiveRecord/Persistence/update_column 对于 3.1+,使用 assign_attributes apidock.com/rails/ActiveRecord/Base/assign_attributes 【参考方案1】:

您可以使用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.rbhttps://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment.rb

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

【讨论】:

清晰而简短。谢谢。 在.attributes = val的情况下,如果您的模型has_one和accepts_nested_attributes_for另一个模型,传递that_model_attributes(没有id)将删除现有的has_one模型,即使您没有坚持(例如保存)。但 assign_attributes 的行为并非如此。【参考方案2】:

我相信您正在寻找的是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 =&gt; :admin ;) @Robin 或者简单地说:attr_protected :is_admin。或者:attr_accessible :name 在这个例子中,:is_admin 是受保护的。我还应该注意,尝试使用.assign_attributes 批量分配受保护的属性确实会引发ActiveModel::MassAssignmentSecurity::Error,即使示例中没有显示。 是的,但我的台词来自您链接到的文档。我只是说您应该复制/粘贴整个示例。但是,是的,你可以说它是受保护的。 @Robin 我将更新该示例,使其更加具体。文档中的示例也有点误导,因为它没有提到 user.assign_attributes( :name =&gt; 'Josh', :is_admin =&gt; true ) 引发错误消息并且实际上没有设置用户的 name 属性。 assign_attributes 从 Rails 3.1 开始可用,因此如果您仍在运行旧版本的 Rails,则无法使用它。【参考方案3】:

要在不保存的情况下将值批量分配给 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= 与 Rails 3 中的 assign_attributes 略有不同。attributes= 将检查传递给它的参数是否为 Hash,如果不是则立即返回; assign_attributes 没有这样的哈希检查。请参阅ActiveRecord Attribute Assignment API documentation for attributes=

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

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

attributes= 会默默地表现得好像分配成功了,但实际上并非如此。

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

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

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

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

这些例子可能看起来有些做作,但在某种程度上,这种类型的错误很容易在从 API 转换数据时出现,甚至只是使用一系列数据转换而忘记了Hash[] 的结果最终.map。保留上面 50 行的一些代码,并从属性分配中删除 3 个函数,这样你就有了失败的秘诀。

Rails 3 的教训是:总是使用assign_attributes 而不是attributes=

导轨 4

在 Rails 4 中,attributes= 只是assign_attributes 的别名。请参阅ActiveRecord Attribute Assignment API documentation for attributes=

在 Rails 4 中,任何一种方法都可以互换使用。未能将 Hash 作为第一个参数传递将导致一个非常有用的异常: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 之前处理任何验证问题。

【讨论】:

【参考方案4】:

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

@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

【讨论】:

以上是关于Rails update_attributes 没有保存?的主要内容,如果未能解决你的问题,请参考以下文章

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

Rails form_with(remote:true)错误

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

ruby update_attribute.rb

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

fe_sendauth:Ruby没有提供密码(PG :: ConnectionBad),但在Rails中没问题