シリアル化された列を持つモデルが、保存されたデータを適切にロードしないという Ruby on Rails の問題を切り分けました。
入ってくるのはハッシュで、出てくるのはフォーマットの問題のために解析できない YAML 文字列です。シリアライザーは、与えられたものを適切に保存および取得できると期待しているため、何か問題が発生したようです。
問題の厄介な文字列は、次のようにフォーマットされています。
message_text = <<END
X
X
END
yaml = message_text.to_yaml
puts yaml
# =>
# --- |
#
# X
# X
puts YAML.load(yaml)
# => ArgumentError: syntax error on line 3, col 0: ‘X’
改行、インデントされた 2 行目、およびインデントされていない 3 行目の組み合わせにより、パーサーが失敗します。空白行またはインデントのいずれかを省略すると問題が解決するように見えますが、これはシリアライゼーション プロセスのバグのようです。かなり特殊な一連の状況が必要になるため、これは適切に処理されていない奇妙なエッジ ケースであると確信しています。
Ruby に同梱され、Rails で使用される YAML モジュールは、処理の大部分を Syck に委譲するように見えますが、送信するデータをエンコードする方法に関するいくつかのヒントを Syck に提供します。
yaml/rubytypes.rb には String#to_yaml の定義があります:
class String
def to_yaml( opts = {} )
YAML::quick_emit( is_complex_yaml? ? self : nil, opts ) do |out|
if is_binary_data?
out.scalar( "tag:yaml.org,2002:binary", [self].pack("m"), :literal )
elsif to_yaml_properties.empty?
out.scalar( taguri, self, self =~ /^:/ ? :quote2 : to_yaml_style )
else
out.map( taguri, to_yaml_style ) do |map|
map.add( 'str', "#{self}" )
to_yaml_properties.each do |m|
map.add( m, instance_variable_get( m ) )
end
end
end
end
end
end
「:」で始まり、デシリアライズ時に Symbol と混同される可能性がある文字列のチェックがあるようです。:quote2 オプションは、エンコード プロセス中にそれを引用することを示す必要があります。上記の条件をキャッチするためにこの正規表現を調整しても、出力には何の影響もないように見えるので、YAML の実装に詳しい人がアドバイスしてくれることを願っています。