Rails update_attributes没有保存?

时间:2011-07-21 01:22:07

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4 rails-activerecord

是否存在不保存记录的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 个答案:

答案 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_attributesattributes=(它们是相同的)

更新方法备忘单(适用于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_attributesattributes=方法。这些方法在Rails 3和更新版本中可用。但是,有一些细微的差异和版本相关的问题需要注意。

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

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

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

请注意,这两种方法都不会执行验证或执行回调; <{1}}被调用时将发生回调和验证。

Rails 3

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

在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.之前预先执行作业,您可能也有兴趣在保存之前进行验证。您可以使用savevalid?方法。两者都返回布尔值。如果未保存的模型通过所有验证,则invalid?返回true,否则返回false。 valid?只是invalid?

的倒数

valid?可以像这样使用:

valid?

这使您能够在调用@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid? 之前处理任何验证问题。