Ruby on Rails を使用すると、シリアル化されたフィールドがいくつかあります (主に配列またはハッシュ)。それらのいくつかにはBigDecimal
s が含まれています。これらの大きな小数が大きな小数のままであることは非常に重要ですが、Rails はそれらを浮動小数に変えています。BigDecimal
s を戻すにはどうすればよいですか?
この問題を調べると、Rails を使用せずにプレーンな Ruby で大きな 10 進数をシリアル化すると、期待どおりに動作することがわかりました。
BigDecimal.new("42.42").to_yaml
=> "--- !ruby/object:BigDecimal 18:0.4242E2\n...\n"
しかし、Rails コンソールではそうではありません:
BigDecimal.new("42.42").to_yaml
=> "--- 42.42\n"
その数値は大小数の文字列表現なので、問題ありません。しかし、読み返すと浮動小数点数として読み取られるため、変換してもBigDecimal
(エラーが発生しやすいのでやりたくないことです)、精度が失われる可能性があり、これは受け入れられません私のアプリ。
activesupport-3.2.11/lib/active_support/core_ext/big_decimal/conversions.rb
BigDecimal で次のメソッドをオーバーライドする原因を突き止めました。
YAML_TAG = 'tag:yaml.org,2002:float'
YAML_MAPPING = { 'Infinity' => '.Inf', '-Infinity' => '-.Inf', 'NaN' => '.NaN' }
# This emits the number without any scientific notation.
# This is better than self.to_f.to_s since it doesn't lose precision.
#
# Note that reconstituting YAML floats to native floats may lose precision.
def to_yaml(opts = {})
return super if defined?(YAML::ENGINE) && !YAML::ENGINE.syck?
YAML.quick_emit(nil, opts) do |out|
string = to_s
out.scalar(YAML_TAG, YAML_MAPPING[string] || string, :plain)
end
end
なぜ彼らはそれをするのでしょうか? さらに重要なことに、どうすれば回避できますか?