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