Почему я получаю эту ошибку "не могу изменить замороженный хэш"?
у меня есть модель человека и модель товара. У человека много предметов, и предмет принадлежит человеку.
в этом коде мне нужно удалить существующие элементы для человека и создать новые из параметра (который является массивом хэшей). Затем мне нужно обновить одно из полей элемента на основе одного из его других полей.
@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
как я могу это исправить? Спасибо за чтение.
4 ответов
Я подозреваю
ActiveSupport::JSON.decode(params["person_items"])
возвращает замороженный хэш, который затем используется для создания объектов
@person.person_items.create(pi) if pi.is_a?(Hash)
и поскольку он заморожен, вы не можете его изменить.
Вы можете
A Сделать глубокую копию объекта JSON
или
B Перезагрузите экземпляр модели, который должен восстановить объект, размораживающий поля.
вариант A - это "лучшее" решение, но трудное, потому что единственный способ, который я знаю о deep копирование-это сериализация и десериализация, а также объект на месте и присвоение возвращаемого значения.
Если вы используете q.уничтожить перед сохранением элемента, то вы получите ошибку. лучше сначала сохранить элемент, а затем использовать destroy.
вы можете обойти это, если вы снова прочитаете person_items из базы данных, а не используете ассоциацию. Ассоциация является устаревшей и указывает на разрушенные строки.
вместо
@person.person_items.each do |x|
попробовать
PersonItem.where(:person_id=>@person.id).each do |x|
вы можете сделать глубокую копию любого объекта в rails включает JSON, так что просто сделайте это.
Запомните это clone
сохраняет замороженное состояние, в то время как dup
нет.
самый простой способ исправить ошибку can't modify frozen Array
- это dup
этот замороженный массив ;)
person_items_from_param = ActiveSupport::JSON.decode(params["person_items"]).dup