关于ruby:Rails update_attributes没有保存?

Rails update_attributes without save?

是否有一个替代update_attributes不保存记录?

所以我可以这样做:

1
2
3
4
5
@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',但我想在一行上更新它们。


我相信你要找的是assign_attributes

它与update_attributes基本相同,但不保存记录:

1
2
3
4
5
6
7
8
9
10
11
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


您可以使用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


您可以使用'attributes'方法:

1
@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宏指定可以访问的属性。然后,不允许将未包含在其中的所有属性进行质量分配。

1
2
3
4
5
6
7
8
9
10
11
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

要在不保存的情况下将值大量分配给ActiveRecord模型,请使用assign_attributesattributes=方法。这些方法在Rails 3和更新版本中可用。但是,有一些细微的差别和版本相关的问题需要注意。

两种方法都遵循以下用法:

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

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

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

Rails 3

attributes=与Rails 3中的assign_attributes略有不同。attributes=将检查传递给它的参数是否为Hash,如果不是,则立即返回; assign_attributes没有这样的哈希检查。请参阅attributes=的ActiveRecord属性分配API文档。

只需在不设置属性的情况下返回,以下无效代码将无声地失败:

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

attributes=将默默地表现得就像分配成功,但实际上,它们不是。

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

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

assign_attributes将为stringify_keys引发NoMethodError异常,表示第一个参数不是哈希。异常本身并不能提供有关实际原因的信息,但异常确实发生的事实非常重要。

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

这些示例可能看似人为,并且它们在一定程度上,但是当从API转换数据时,甚至只是使用一系列数据转换并忘记Hash[]最终结果。保留一些代码50行以上,并从属性赋值中删除3个函数,并且您有失败的配方。

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

Rails 4

在Rails 4中,attributes=只是assign_attributes的别名。请参阅attributes=的ActiveRecord属性分配API文档。

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

验证

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

valid?可以像这样使用:

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

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