是否存在不保存记录的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'
,但我想在一行上更新它们。
答案 0 :(得分:566)
我相信你要找的是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
答案 1 :(得分:157)
您可以使用assign_attributes
或attributes=
(它们是相同的)
更新方法备忘单(适用于Rails 4):
update_attributes
= assign_attributes
+ save
attributes=
= assign_attributes
update
= update_attributes
<强>来源:强>
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
答案 2 :(得分:63)
您可以使用'attributes'方法:
@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
答案 3 :(得分:8)
要在不保存的情况下将值分配给ActiveRecord模型,请使用assign_attributes
或attributes=
方法。这些方法在Rails 3和更新版本中可用。但是,有一些细微的差异和版本相关的问题需要注意。
这两种方法都遵循这种用法:
@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }
@user.attributes = { model: "Sierra", year: "2012", looks: "Sexy" }
请注意,这两种方法都不会执行验证或执行回调; <{1}}被调用时将发生回调和验证。
save
与Rails 3中的attributes=
略有不同。assign_attributes
将检查传递给它的参数是否为Hash,如果不是,则立即返回; attributes=
没有此类哈希检查。请参阅ActiveRecord Attribute Assignment API documentation for attributes=
。
以下无效代码将通过简单地返回而不设置属性而无声地失败:
assign_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=
引发异常以通知错误已发生。
这些示例可能看似人为,并且它们在一定程度上,但在从API转换数据时,甚至只是使用一系列数据转换并忘记assign_attributes
结果时,很容易发生此类错误最终的Hash[]
。保留一些代码50行以上,并从属性赋值中删除3个函数,并且你有一个失败的秘诀。
Rails 3的教训是这样的:总是使用.map
代替assign_attributes
。
在Rails 4中,attributes=
只是attributes=
的别名。请参阅ActiveRecord Attribute Assignment API documentation for attributes=
。
使用Rails 4,任何一种方法都可以互换使用。如果未能将Hash作为第一个参数传递,则会产生一个非常有用的异常:assign_attributes
如果您在准备ArgumentError: When assigning attributes, you must pass a hash as an argument.
之前预先执行作业,您可能也有兴趣在保存之前进行验证。您可以使用save
和valid?
方法。两者都返回布尔值。如果未保存的模型通过所有验证,则invalid?
返回true,否则返回false。 valid?
只是invalid?
valid?
可以像这样使用:
valid?
这使您能够在调用@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid?
之前处理任何验证问题。