Поля ActiveModel::Dirty и JSON

Я использую ActiveModel::Dirty для отслеживания изменений, внесенных в форму. Теперь все работает так, как я ожидаю. С такими вещами, как номера телефонов, которые получают тире в форме, я просто форматирую их, и тогда номер телефона не будет отображаться в списке .changed, что является ожидаемым поведением.

Однако я столкнулся с проблемой, когда я использую поле jsonb в моей модели профиля. Таким образом, проблема в том, что ActiveModel перечислит поле JSONB как измененное, даже если я отформатирую его специально, чтобы оно соответствовало тому, как оно выглядело раньше. Это не ожидаемое поведение. Что еще более странно, так это то, что другой столбец JSONB, который у меня есть, не испытывает этого безумия.

Поле JSONB, с которым у меня возникли проблемы, выглядит так: store_accessor :user_details, :names, :other_field store_accessor :bank_details, :bank_city, :bank_name user_details и bank_details являются столбцами jsonb. Некоторые вещи, на которые стоит обратить внимание: имена — это массив, а другое_поле — это строка. bank_city и bank_name являются строками.

Может ли кто-нибудь пролить свет на то, почему именно :user_details борется с этой проблемой, а не столбец :bank_details JSON?

Я подозреваю, что это может быть связано с тем, что я использую массив в :user_details, и я подозреваю, что сравнение отбрасывается где-то в исходном коде ActiveModel, но, может быть, я ошибаюсь?

Изменить: я обнаружил, что это определенно потому, что я использую массив для :names. Я изменил его на строку, и он перестал думать, что столбец JSON был изменен. Собираюсь копаться в исходном коде ActiveModel, чтобы посмотреть, смогу ли я найти причину.

Редактировать № 2: По какой-то причине я думал, что решил проблему, ничего не делая, но я манекен и понял, что удалил что-то в форме. Так что этот вопрос до сих пор не решен для меня. Любое понимание было бы удивительным. Я не могу понять из исходного кода ActiveModel::Dirty, почему это происходит. Я не совсем уверен, где искать. Собираюсь шлепнуть byebugs, чтобы посмотреть, поможет ли это.

Редактировать № 3: шаги, чтобы повторить эту проблему

Создайте модель рельсов со столбцом JSONB. Установите аксессуары для магазина, которые вам нужны для этого. По умолчанию используйте либо валидатор, либо средство форматирования, чтобы он был пустым массивом. Дайте вашей модели ActiveModel::Dirty include. Запустите консоль рельсов. выполните следующие команды. Представьте, что user_details — это столбец JSONB, а его метод доступа к хранилищу — имена.

  a = Profile.user_details
  a.user_details = { "names" => [{"first_name" => "", "last_name" => "" }] } # This is to replicate what it would look like in a form when a user is submitting a blank entry.
  a.changed # This will show that user_details has changed which is correct
  a.names = []
  a.changed # This will still show that user_details has changed even though it has been set back to its initial state of an empty array. This would work if it was a string field instead of an array.

person Gabriel    schedule 26.11.2018    source источник


Ответы (1)


После открытия задачи на Rails Github я получил ответ https://github.com/rails/rails/issues/34537#issuecomment-442265161

Мне сказали, что изменение принудительно осуществляется через атрибуты для типов json, jsonb, hstore и сериализованных атрибутов. Исходный код здесь: https://github.com/rails/rails/blob/06ab7b27ea1c1ab357085439abacdb464f6742bf/activerecord/lib/active_record/store.rb#L181

Причина, по которой я столкнулся с этим, заключается в том, что я больше не пытаюсь пытаться, поскольку проект, над которым я работаю, не будет использовать ActiveModel:: Dirty и не будет пытаться отслеживать изменения так, как я пытался сделать это.

Так что всем будущим поколениям, которые столкнутся с этой проблемой, удачи и не стесняйтесь обращаться к этой проблеме с github и жаловаться на то, что это не работает.

person Gabriel    schedule 28.11.2018