Rails JSON Serialization of Decimal adds Quotes
The only "safe" way to hand decimals from language A to language B is to use a String. If your json contains "rating": 98.79999999999999
it will probably be converted to 98.79999999999998
by your JavaScript runtime.
See BigDecimal as_json documentation:
A BigDecimal would be naturally represented as a JSON number. Most libraries, however, parse non-integer JSON numbers directly as floats. Clients using those libraries would get in general a wrong number and no way to recover other than manually inspecting the string with the JSON code itself.
That’s why a JSON string is returned. The JSON literal is not numeric, but if the other end knows by contract that the data is supposed to be a BigDecimal, it still has the chance to post-process the string and get the real value.
If you want to force Rails not to quote these, you could monkey-patch BigDecimal (see Rails source).
# not needed: to compare with the Numeric implementation
class Numeric
def as_json(options = nil) self end #:nodoc:
def encode_json(encoder) to_s end #:nodoc:
end
class BigDecimal
def as_json(options = nil) self end
def encode_json(encoder) to_s end #:nodoc:
end
This has changed for Rails 4.0 which has the option ActiveSupport.encode_big_decimal_as_string
so that you can specify your BigDecimal serialization preference. See issue 6033
In the meantime, if you're comfortable with the arguments put forward in 6033 and you're running a Rails version lower than 4.0 you can monkey patch BigDecimal as below
require 'bigdecimal'
class BigDecimal
def as_json(options = nil) #:nodoc:
if finite?
self
else
NilClass::AS_JSON
end
end
end
This solved my issues with RABL pumping out strings for dollar amounts stored as BigDecimal.
if you are using ActiveModel::Serializer you can also use to_f to force the conversion from Decimal to Float type. that wil also trim out the quote for you!
so in your object serializer class. do
def rating
self.rating.to_f
end