Что происходит и почему
ActionController::Parameters
(то, с чем params
работает в контроллерах) используется для наследования от HashWithIndifferentAccess
, который наследуется от Hash
.Таким образом, ActionController::Parameters < Hash
имел обыкновение быть истинным, как если бы что-то вроде:
params.require(:x).permit(some_hash: %i[key1 key2]).is_a? Hash
Если вы копали Hash
из params
:
some_hash = params.require(:x).permit(some_hash: ...)
и сериализовали это вмодель:
class M < ApplicationRecord # Or ActiveRecord::Base in the past
serialize :h, Hash
end
#...
m.h = some_hash
вы можете получить в своей базе данных такой код YAML, как этот:
--- !ruby/object:ActionController::Parameters
...
, а не ожидаемый простой хэш YAMLized.
Но тогда Rails5ActionController::Parameters
больше не наследуется от Hash
:
- Make
ActionController::Parameters
больше не наследуется от HashWithIndifferentAccess
.
и вызов to_h
или to_hash
для ActionController::Parameters
теперь вызывает исключение.
Если вы обновляете свой код и пытаетесь загрузить модель с сериализованными данными в нем:
serialize :h, Hash
затем модель загрузит текст из h
, проанализирует YAML, чтобы получить экземпляр ActionController::Parameters
, и вызовет to_h
для него, чтобы убедиться, что у него есть хэш, и вы получите исключение.
Что с этим делать
Есть пара вещей, которые вам нужно сделать:
- Исправьте ваши контроллеры, чтобы убедиться, что они получают настоящий хэшs из
params
. - Исправьте ваши данные таким образом, чтобы вы использовали сериализованные хэши, а не
ActionController::Parameters
экземпляров.
Исправление контроллеров - это простой вопрос вызова to_unsafe_h
на параметры, которые еще не являются реальными хешами.
Исправление данных более утомительно.Я бы, вероятно, просмотрел таблицы с использованием низкоуровневого интерфейса базы данных (т.е. нигде не было ActiveRecord), прочитал бы YAML из каждой строки, YAML.load
, преобразовал бы его в хеш, вызвав для него to_unsafe_h
, и затем записал быназад the_real_hash.to_yaml
текст.Вы можете использовать фильтр like '--- !ruby/object:ActionController::Parameters%'
в предложении WHERE только для разбитых строк.
Я также настоятельно рекомендую вам прекратить использование serialize
, пока вы там.serialize
является чем-то вроде клочья, и в базе данных нет нормального способа работы с YAML;теперь в этом также нет необходимости, поскольку PostgreSQL и MySQL имеют встроенную поддержку JSON (но я не уверен, насколько хорошо ActiveRecord поддерживает JSON MySQL).