Active Record сериализовал потерянные строковые кодировки attr (вероятно, проблема YAML), обходные пути? - PullRequest
4 голосов
/ 02 сентября 2010

Я использую Rails 2.3.8 с Ruby 1.9.1, и у меня проблема с сериализованные атрибуты в активной записи, не сохраняющие строковые кодировки. Основная проблема, вероятно, yaml, но мне интересно, если у кого-то есть любые хорошие идеи о том, как справиться с этим. Приложение, над которым я работаю, имеет многочисленные сериализованные поля, некоторые из которых содержат глубокие структуры массивы и хэши. Возвращение строки ASCII-8Bit (это на самом деле UTF-8) глубоко внутри этих структур разрушает позже ...

Возможно, лучше всего это проиллюстрировать на примере, если я сохраню l в сериализованном атрибуте в модель активной записи я верну l2 при чтении из базы данных.

>> l
=> ["English", "Türkçe", "Русский"]
>> l.map(&:encoding)
=> [#<Encoding:UTF-8>, #<Encoding:UTF-8>, #<Encoding:UTF-8>]
>> l.map(&:valid_encoding?)
=> [true, true, true]
>> l.to_yaml
=> "--- \n- English\n- !binary |\n  VMO8cmvDp2U=\n\n-
\"\\xD0\\xA0\\xD1\\x83\\xD1\\x81\\xD1\\x81\\xD0\\xBA\\xD0\\xB8\\xD0\\xB9\"\n"
>> l2 = YAML.load(l.to_yaml)
=> ["English", "T\xC3\xBCrk\xC3\xA7e", "Русский"]
>> l2.map(&:encoding)
=> [#<Encoding:UTF-8>, #<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>]

Кто-нибудь знает, как yaml решает, сохранять ли строку как бинарный или как экранированная строка? Обе последние две строки выше не-ascii-7, но только первый хранится в двоичном виде ...

В настоящее время я думаю о том, чтобы подключить активную процедуру десериализации записей, обходить хэши и массивы и принудительно кодировать все строковые элементы. Не очень безопасный или общий, но, вероятно, подойдет для моего варианта использования, хотя мне также интересно, если кто-нибудь залатал YAML, чтобы быть умнее здесь ...

1 Ответ

1 голос
/ 03 сентября 2010

Я придумала одно решение:

monkey patching String может заставить YAML использовать \ escape-, а не двоичный код и, следовательно, возвращать строки в кодировке по умолчанию (для меня UTF-8), а не в ASCII-8BIT

class String
  def is_binary_data?
    encoding == Encoding::ASCII_8BIT unless empty?
  end
end

первоначально в этой подпрограмме используется некоторая эвристика, вокруг которой было бы меньше \ выход из двоичного кодирования строки, поэтому проблемы возникали только с некоторыми международными строками, которые у меня были.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...