I'm using the default JSON serialization for a model that has a number of decimal and integer attributes. An example result is:
{ "user": { "id": 1234, "rating": "98.7" } }
Notice the addition of quotes around the value of "rating". This causes the deserialization library I'm using to incorrectly treat these as strings (instead of decimals). Can Rails be set to not use the quotes for all decimals?
Edit:
I'm on Rails 3.0.7 and Ruby 1.9.2 if that makes a difference.
Edit:
Terminal:
rails g model user rating:decimal
rake db:migrate
Console:
user = User.create(rating: 98.7)
user.to_json
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With