为什么我得到这个'无法修改冻结哈希'错误?

ben*_*ben 11 ruby ruby-on-rails

我有一个Person模型和一个Item模型.一个人有很多项目,一个项目属于一个人.

在此代码中,我需要删除一个人的现有项目,并从参数(这是一个哈希数组)创建新的项目.然后,我需要根据其他一个字段更新项目的一个字段.

@person = Person.find(params["id"])

@person.person_items.each do |q|
    q.destroy
end

person_items_from_param = ActiveSupport::JSON.decode(params["person_items"])

person_items_from_param.each do |pi|
    @person.person_items.create(pi) if pi.is_a?(Hash)
end

@person.person_items.each do |x|
    if x.item_type == "Type1"
        x.item_amount = "5"
    elsif x.item_type == "Type2"
        x.item_amount = "10"
    end
    x.save
end
Run Code Online (Sandbox Code Playgroud)

x.item_amount = "5"&x.item_amount = "10"行上我得到这个错误:

RuntimeError in PersonsController#submit_items
can't modify frozen hash 
Run Code Online (Sandbox Code Playgroud)

我怎样才能解决这个问题?谢谢阅读.

Ena*_*ane 7

我怀疑

ActiveSupport::JSON.decode(params["person_items"])
Run Code Online (Sandbox Code Playgroud)

返回一个冻结的哈希值,然后用它来创建对象

@person.person_items.create(pi) if pi.is_a?(Hash)
Run Code Online (Sandbox Code Playgroud)

而且因为冻结你无法修改它.

你可以

A制作JSON对象的深层副本

要么

B重新加载模型实例,该实例应重新实例化对象,使字段解冻.

选项A是"更好"的解决方案,但很难,因为我知道深度复制的唯一方法是序列化和反序列化以及对象并分配返回值.


小智 6

如果在保存元素之前使用q.destroy,那么您将收到错误.最好先保存元素然后再使用destroy.