2010-12-19 42 views
10

Mam model osoby & model przedmiotu. Osoba ma wiele przedmiotów, a przedmiot należy do osoby.Dlaczego otrzymuję komunikat o błędzie "Nie można zmienić zamrożonego hasha"?

W tym kodzie, muszę usunąć istniejące elementy dla osoby i utworzyć nowe z parametru (który jest tablicą skrótów). Następnie muszę zaktualizować jedno z pól elementu na podstawie jednego z jego pozostałych pól.

@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 

Na x.item_amount = "5" & x.item_amount = "10" liniach dostaję ten błąd:

RuntimeError in PersonsController#submit_items 
can't modify frozen hash 

Jak mogę rozwiązać ten problem? Dziękuje za przeczytanie.

Odpowiedz

7

Podejrzewam

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

zwraca zamrożonego hash który następnie wykorzystać do tworzenia obiektów

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

A ponieważ jego zamrożone nie można go zmodyfikować.

Mogłeś

Zrób głęboki kopię obiektu JSON

lub

B Odśwież instancja model, który powinien reinstantiate celem dokonywania pola odmrożone.

Opcja A jest "lepszym" rozwiązaniem, ale trudnym, ponieważ jedynym sposobem, w jaki znam głębokie kopiowanie, jest serializowanie i deserializacja oraz wprowadzanie obiektów i przypisywanie wartości zwracanej.

+0

Dzięki za odpowiedź. Nie jestem pewien, czy rozumiem, nie próbuję modyfikować obiektu hash/JSON, próbuję zmodyfikować obiekt ActiveRecord, który właśnie utworzyłem. To mogło być nieco mylące w moim kodzie, zmieniłem niektóre z nazw zmiennych, aby spróbować je wyjaśnić. – ben

+0

Wierzę, że ActiveSupport :: JSON.decode (parametry ["person_items"]) tworzy zamrożony skrót.ale po ponownym załadowaniu ActiveRecord po prostu tworzy nowy hasz, który nie jest zamrożony. – EnabrenTane

+0

przeładowanie działa po próbie usunięcia nadrzędnego po usunięciu potomka – Anwar

2

Możesz obejść ten problem, jeśli ponownie czytasz wpisy person_items z bazy danych, zamiast korzystać z powiązania. Związek jest nieaktualny i wskazuje zniszczone rzędy.

Zamiast @person.person_items.each do |x|

Spróbuj PersonItem.where(:person_id=>@person.id).each do |x|

6

Jeśli używasz q.destroy przed elementem oszczędzania wtedy pojawia się błąd. lepiej najpierw ocal element, a potem zniszcz.

+0

To jest poprawne wyjaśnienie. – CppNoob

0

Możesz wykonać głęboką kopię dowolnego obiektu w szynach zawiera JSON, więc po prostu to zrób. Pamiętaj, że clone zachowuje stan zamrożenia, natomiast dup nie.

Najprostszym sposobem, aby naprawić błąd can't modify frozen Array jest dup ten mrożony tablica;)

person_items_from_param = ActiveSupport::JSON.decode(params["person_items"]).dup 
Powiązane problemy