2010-12-19 15 views
10

Tengo un modelo de persona & un modelo de artículo. Una persona tiene muchos elementos y un elemento pertenece a una persona.¿Por qué recibo este error 'no puedo modificar hash congelado'?

En este código, necesito eliminar los elementos existentes para una persona y crear nuevos desde un parámetro (que es una matriz de valores hash). Entonces, necesito actualizar uno de los campos del artículo, basado en uno de sus otros campos.

@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 

En los x.item_amount = "5" & x.item_amount = "10" líneas consigo este error:

RuntimeError in PersonsController#submit_items 
can't modify frozen hash 

¿Cómo puedo solucionar este problema? Gracias por leer.

Respuesta

7

sospecharía

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

devuelve un hash congelada que luego se utiliza para crear objetos

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

Y desde su congelado no puede modificarlo.

Se podría

Un Hacer una copia profunda del objeto JSON

o

B Actualizar la instancia modelo que debe reinstantiate el objeto de hacer los campos no congelada.

La opción A es la solución "mejor" pero difícil porque la única manera que conozco de copiar profundamente es serializar y deserializar objetos en su lugar y asignar el valor de retorno.

+0

Gracias por su respuesta. Aunque no estoy seguro de entender, no estoy tratando de modificar el objeto hash/JSON, estoy tratando de modificar el objeto ActiveRecord que acabo de crear. Esto puede haber sido un poco confuso en mi código, he cambiado algunos de los nombres de las variables para tratar de hacerlo más claro. – ben

+0

Creo que ActiveSupport :: JSON.decode (params ["person_items"]) crea el hash congelado.pero cuando lo vuelva a cargar, ActiveRecord solo instanciará un nuevo hash que no está congelado – EnabrenTane

+0

la recarga funciona cuando se intentó eliminar el elemento principal después de eliminar el elemento secundario – Anwar

2

Puede solucionar esto si vuelve a leer los elementos person de la base de datos en lugar de utilizar la asociación. La asociación está obsoleta y apunta a las filas destruidas.

En lugar de @person.person_items.each do |x|

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

6

Si utiliza q.destroy antes elemento de ahorro por lo que recibirá el error. mejor guarde el elemento primero y luego use destroy.

+0

Esta es la explicación correcta. – CppNoob

0

Puedes hacer una copia profunda de cualquier objeto en los rieles, incluido JSON, así que hazlo. Recuerde que clone conserva el estado congelado, mientras que dup no.

La manera más fácil de reparar el error can't modify frozen Array es dup esta matriz congelada;)

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