Rails JSON Serializing Decimal Adds Quotes

I use default JSON serialization for a model with the number of decimal and integer attributes. Example:

{ "user": { "id": 1234, "rating": "98.7" } } 

Pay attention to adding quotes around the value of "rating". This causes the deserialization library I use to incorrectly treat them as strings (instead of decimals). Can Rails set to not use quotation marks for all decimals?

Edit:

I'm on Rails 3.0.7 and Ruby 1.9.2, if that matters.

Edit:

Terminal:

 rails g model user rating:decimal rake db:migrate 

Console:

 user = User.create(rating: 98.7) user.to_json 
+43
ruby-on-rails
May 25 '11 at 18:02
source share
4 answers

This has changed for Rails 4.0, which has the ActiveSupport.encode_big_decimal_as_string option ActiveSupport.encode_big_decimal_as_string that you can specify the preference for BigDecimal serialization. See question 6033

In the meantime, if you like the argument posed in 6033, and you use a version of Rails below 4.0, you can decapitate BigDecimal, as shown below

 require 'bigdecimal' class BigDecimal def as_json(options = nil) #:nodoc: if finite? self else NilClass::AS_JSON end end end 

This solved my problems with RABL, deflating rows for dollar amounts stored as BigDecimal.

+26
Jul 07 '13 at 4:47 on
source share

The only "safe" way to pass decimals from A to B is to use String. If your json contains a "rating": 98.79999999999999 , it will probably be converted to 98.79999999999998 according to your JavaScript runtime.

See the BigDecimal as_json documentation:

BigDecimal will be naturally represented as a JSON number. Most libraries, however, parse non-integer JSON numbers just like floating ones. Customers using these libraries get generally the wrong number and there is no way to recover from manually checking the string using JSON code itself.

This is why the JSON string is returned. The JSON literal is not numeric, but if the other end knows by contract that the data must be BigDecimal, it still has a chance to render the string and get the real value.

If you want to force Rails not to quote them, you can decapitate BigDecimal (see the 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 
+38
May 25 '11 at 23:17
source share

if you use ActiveModel :: Serializer, you can also use to_f to force decimal to float conversion. that you will also steal a quote for you!

therefore, in the class of objects of the serializer. do

 def rating self.rating.to_f end 
+9
May 27 '13 at 2:40
source share

With Rails 5, encode_big_decimal_as_string does not work (this was deprecated, therefore not surprising).

If you add jbuilder to your application

 # Gemfile gem 'jbuilder', '~> 2.5' 

Then just create a json representation that drops the decimal in the float just for the representation, you have to be gold.

 # app/views/yourmodel/index.json.jbuilder json.array! @yourmodels do |yourmodel| json.attributethatisadecimal yourmodel.attributethatisadecimal.to_f end 

This worked for me - a bit more work (because you need to map your model to jbuilder), but this approach seems pretty clean.

0
Mar 27 '17 at 5:39 on
source share



All Articles