【问题标题】:Rails update_attributes without save?Rails update_attributes 没有保存?
【发布时间】: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',但我想在一行上更新它们。

【问题讨论】:

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


【解决方案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.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 = 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
    

    【讨论】:

      猜你喜欢
      • 2017-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      • 1970-01-01
      • 1970-01-01
      • 2016-11-13
      相关资源
      最近更新 更多