2010-12-19 60 views
10

我有一個人模型&一個項目模型。一個人有很多物品,一個物品屬於一個人。爲什麼我得到這個'不能修改冷凍散列'錯誤?

在這段代碼中,我需要刪除一個人的現有項目,並從一個參數(這是一個散列數組)創建新的項目。然後,我需要根據其中一個字段更新其中一個項目的字段。

@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 

x.item_amount = "5" & x.item_amount = "10"線我得到這個錯誤:

RuntimeError in PersonsController#submit_items 
can't modify frozen hash 

我該如何解決這個問題?謝謝閱讀。

回答

7

我會懷疑

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

返回冷凍哈希,你再使用創建對象

@person.person_items.create(pi) if pi.is_a?(Hash) 

而且因爲其凍結則不能進行修改。

你可以

一個 讓JSON對象

乙 刷新模型實例應該重新實例化對象製作領域解凍的深層副本。

選項A是「更好」的解決方案,但很困難,因爲我知道深度複製的唯一方法是序列化和反序列化,並在適當位置對象並分配返回值。

+0

謝謝您的回答。我不確定我是否理解,但我不想修改散列/ JSON對象,我試圖修改剛剛創建的ActiveRecord對象。這在我的代碼中可能有點令人困惑,我已經改變了一些變量名來嘗試使它更清晰。 – ben 2010-12-19 06:05:45

+0

我相信ActiveSupport :: JSON.decode(params [「person_items」])創建凍結哈希。但是當你重新加載它時,ActiveRecord會實例化一個新的未被凍結的哈希 – EnabrenTane 2011-01-07 02:19:30

+0

當刪除子時試圖刪除父項時重新加載工作 – Anwar 2016-04-10 18:29:26

2

如果您再次從數據庫中讀取person_items而不是使用關聯,則可以解決此問題。該協會陳舊,指向被毀壞的行。

而不是 @person.person_items.each do |x|

嘗試 PersonItem.where(:person_id=>@person.id).each do |x|

6

如果使用q.destroy節省元素之前,那麼你會得到錯誤。最好先保存元素,然後使用destroy。

+0

這是正確的解釋。 – CppNoob 2017-11-23 01:05:54

0

你可以在rails中包含任何對象的深層副本包含JSON,所以就這樣做。 請記住clone保留凍結狀態,而dup不會。修正錯誤can't modify frozen Array

最簡單方法是dup這個冷凍陣列;)

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