Ruby-on-rails 为什么我会收到“无法修改冻结哈希”错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4481790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why am I getting this 'can't modify frozen hash' error?
提问by ben
I have a Person model & an Item model. A person has many items, and an item belongs to a person.
我有一个 Person 模型和一个 Item 模型。一个人有很多物品,一个物品属于一个人。
In this code, I need to delete the existing items for a person, and create new ones from a parameter (which is an array of hashes). Then, I need to update one of the item's fields, based on one of its other fields.
在这段代码中,我需要删除一个人的现有项目,并从一个参数(它是一个哈希数组)创建新项目。然后,我需要根据项目的其他字段之一更新项目的字段之一。
@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
On the x.item_amount = "5"& x.item_amount = "10"lines I get this error:
在x.item_amount = "5"&x.item_amount = "10"行上,我收到此错误:
RuntimeError in PersonsController#submit_items
can't modify frozen hash
How can I fix this? Thanks for reading.
我怎样才能解决这个问题?谢谢阅读。
采纳答案by EnabrenTane
I would suspect
我会怀疑
ActiveSupport::JSON.decode(params["person_items"])
returns a frozen hash which you then use to create objects
返回一个冻结的哈希值,然后你用它来创建对象
@person.person_items.create(pi) if pi.is_a?(Hash)
And since its frozen you can't modify it.
而且由于它被冻结,你无法修改它。
You could
你可以
A Make a deep copy of the JSON object
A 制作 JSON 对象的深层副本
or
或者
B Reload the model instance which should reinstantiate the object making the fields unfrozen.
B 重新加载模型实例,它应该重新实例化对象,使字段解冻。
Option A is the "better" solution but difficult because the only way I know of deep copying is serializing and deserializing and object in place and assigning the return value.
选项 A 是“更好”的解决方案,但很困难,因为我所知道的深度复制的唯一方法是序列化和反序列化以及对象到位并分配返回值。
回答by AahladParadigm
If you use q.destroy before saving element then you will get the error. better save the element first and then use destroy.
如果在保存元素之前使用 q.destroy 那么你会得到错误。最好先保存元素,然后使用销毁。
回答by Aaron Henderson
You can get around this if you read the person_items from the database again rather than using the association. The association is stale and pointing to the destroyed rows.
如果您再次从数据库中读取 person_items 而不是使用关联,则可以解决此问题。该关联是陈旧的并指向被破坏的行。
Instead of
@person.person_items.each do |x|
代替
@person.person_items.each do |x|
Try
PersonItem.where(:person_id=>@person.id).each do |x|
尝试
PersonItem.where(:person_id=>@person.id).each do |x|
回答by eudaimonia
You can make a deep copy of any object in rails includes JSON, so just do it.
Remember that clonepreserves the frozen state, while dupdoesn't.
您可以在 rails includes JSON 中制作任何对象的深层副本,所以就这样做吧。请记住,clone保留冻结状态,而dup不会。
Easiest way to fix error can't modify frozen Arrayis to dupthis frozen array ;)
修复错误的最简单方法can't modify frozen Array是使用dup此冻结数组;)
person_items_from_param = ActiveSupport::JSON.decode(params["person_items"]).dup

