2010-12-19 10 views
10

私はPersonモデル&を持っています。人には多くのアイテムがあり、アイテムは人に属します。「フリーズハッシュを修正できません」というエラーが表示されるのはなぜですか?

このコードでは、人物の既存のアイテムを削除し、パラメータ(ハッシュの配列)から新しいアイテムを作成する必要があります。次に、アイテムのフィールドの1つを他のフィールドの1つに基づいて更新する必要があります。 x.item_amount = "5" & x.item_amount = "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 

私はこのエラーを取得する:

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オブジェクトのディープコピーを作成します

または

B は、フィールドが凍結されていない作ったオブジェクトを再インスタンスすべきモデルインスタンスをリロードします。

オプションAは「より良い」解決策ですが、深いコピーがわかっている唯一の方法は、シリアライズとデシリアライズを行い、戻り値を割り当てることです。

+0

感謝。私はハッシュ/ JSONオブジェクトを変更しようとしていませんが、私が作成したばかりのActiveRecordオブジェクトを変更しようとしています。これは私のコードでは少し混乱しているかもしれませんが、私はいくつかの変数名を変更してより明確にしようとしました。 – ben

+0

私は、ActiveSupport :: JSON.decode(params ["person_items"])がフリーズされたハッシュを作成すると信じています。あなたがそれをリロードすると、ActiveRecordはフリーズされていない新しいハッシュをインスタンス化します – EnabrenTane

+0

リロードは、子を削除した後に親を削除しようとすると動作します – Anwar

2

アソシエーションを使用するのではなく、データベースからperson_itemsを再度読み取ると、この問題を回避できます。関連は古く、破壊された行を指しています。代わりに @person.person_items.each do |x|

は、あなたが要素を保存する前にq.destroyを使用している場合、あなたはエラーになります PersonItem.where(:person_id=>@person.id).each do |x|

6

を試してみてください。最初に要素を保存してから、破棄を使用してください。

+0

これは正しい説明です。 – CppNoob

0

レール内のオブジェクトの深いコピーにJSONが含まれているようにすることができます。 cloneはフリーズ状態を保持し、dupはフリーズ状態を保持します。エラーcan't modify frozen Arrayを修正する

最も簡単な方法は、dupに、この凍結された配列である;)あなたの答えのための

person_items_from_param = ActiveSupport::JSON.decode(params["person_items"]).dup 
関連する問題