Rails JSON Сериализация Decimal добавляет цитаты - PullRequest
45 голосов
/ 25 мая 2011

Я использую сериализацию JSON по умолчанию для модели, которая имеет ряд десятичных и целочисленных атрибутов. Пример результата:

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

Обратите внимание на добавление кавычек вокруг значения «рейтинг». Это приводит к тому, что библиотека десериализации, которую я использую, неправильно обрабатывает их как строки (вместо десятичных). Можно ли в Rails не использовать кавычки для всех десятичных дробей?

Edit:

Я на Rails 3.0.7 и Ruby 1.9.2, если это имеет значение.

Изменить:

Терминал:

rails g model user rating:decimal
rake db:migrate

Консоль

user = User.create(rating: 98.7)
user.to_json

Ответы [ 4 ]

42 голосов
/ 26 мая 2011

Единственный «безопасный» способ передачи десятичных знаков с языка A на язык B - это использование строки.Если ваш json содержит "rating": 98.79999999999999, он, вероятно, будет преобразован в 98.79999999999998 вашей средой выполнения JavaScript.

См. BigDecimal as_json документация:

BigDecimal будетбыть естественно представлен в виде числа JSON.Однако большинство библиотек анализируют нецелые числа JSON непосредственно как числа с плавающей точкой.Клиенты, использующие эти библиотеки, обычно получают неверное число и не могут восстановить, кроме как вручную проверять строку с помощью самого кода JSON.

Вот почему возвращается строка JSON.Литерал JSON не является числовым, но если по контракту другой конец знает, что данные должны быть BigDecimal, у него все еще есть возможность пост-обработки строки и получения действительного значения.

Если вы хотите заставить Rails не заключать их в кавычки, вы можете сделать патч BigDecimal (см. 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
28 голосов
/ 07 июля 2013

Это изменилось для Rails 4.0, у которого есть опция ActiveSupport.encode_big_decimal_as_string, так что вы можете указать свой предпочтительный вариант сериализации BigDecimal. См. Выпуск 6033

Тем временем, если вам не безразличны аргументы, выдвинутые в 6033, и вы используете версию Rails ниже 4.0, вы можете сделать патч BigDecimal обезьяны, как показано ниже

require 'bigdecimal'

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

Это решило мои проблемы с откачкой строк RABL для долларовых сумм, хранящихся в виде BigDecimal.

10 голосов
/ 27 мая 2013

если вы используете ActiveModel :: Serializer, вы также можете использовать to_f для принудительного преобразования из типа Decimal в Float.это также обрезает для вас цитату!

в вашем классе сериализатора объектов.делать

def rating
  self.rating.to_f
end
0 голосов
/ 27 марта 2017

С Rails 5 encode_big_decimal_as_string не работает (это устарело, поэтому нет ничего удивительного).

Если вы добавляете jbuilder в ваше приложение

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

Затем просто создайте представление json, котороебросает десятичную дробь в число с плавающей точкой только для вида, вы должны быть золотыми.

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

Это хорошо сработало для меня - немного больше работы (потому что вы должны отобразить свою модель на jbuilder), но этот подход кажетсядовольно чисто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...