Rails JSON Сериализация десятичных добавлений Цитаты
Я использую сериализацию JSON по умолчанию для модели с числом десятичных и целочисленных атрибутов. Пример:
{ "user": { "id": 1234, "rating": "98.7" } }
Обратите внимание на добавление котировок вокруг значения "рейтинг". Это приводит к тому, что библиотека десериализации я использую, чтобы неправильно рассматривать их как строки (вместо десятичных знаков). Может ли Rails установить, чтобы не использовать кавычки для всех десятичных знаков?
Edit:
Я на Rails 3.0.7 и Ruby 1.9.2, если это имеет значение.
Edit:
Терминал:
rails g model user rating:decimal
rake db:migrate
Консоль:
user = User.create(rating: 98.7)
user.to_json
Ответы
Ответ 1
Это изменилось для 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.
Ответ 2
Единственным "безопасным" способом передачи десятичных знаков с языка A на язык B является использование String. Если ваш json содержит "rating": 98.79999999999999
, он, вероятно, будет преобразован в 98.79999999999998
по вашей среде выполнения JavaScript.
Смотрите документацию BigDecimal as_json:
BigDecimal будет естественным представленный как номер JSON. Наиболее библиотеки, однако, анализируют нецелые JSON номера прямо как плавающие. Клиенты, использующие эти библиотеки, получить вообще неправильный номер и нет способ восстановления не вручную проверка строки с помощью JSON самого кода.
Вот почему возвращается строка JSON. Литерал JSON не является числовым, но если другой конец знает по контракту что данные должны быть BigDecimal, у него все еще есть шанс постобразить строку и получить реальная стоимость.
Если вы хотите заставить Rails не процитировать их, вы можете обезглавить BigDecimal (см. Rails источник).
# 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
Ответ 3
если вы используете ActiveModel:: Serializer, вы также можете использовать to_f для принудительного преобразования из десятичного в тип Float. что вы также украдете цитату для вас!
поэтому в классе объектов сериализатора. do
def rating
self.rating.to_f
end
Ответ 4
С Rails 5 encode_big_decimal_as_string не работает (это было устаревшим, поэтому не удивительно).
Если вы добавите jbuilder в свое приложение
# Gemfile
gem 'jbuilder', '~> 2.5'
Затем просто создайте json-представление, которое отбрасывает десятичное число в float только для представления, вы должны быть золотыми.
# app/views/yourmodel/index.json.jbuilder
json.array! @yourmodels do |yourmodel|
json.attributethatisadecimal yourmodel.attributethatisadecimal.to_f
end
Это сработало для меня - немного больше работы (потому что вам нужно сопоставить свою модель с jbuilder), но этот подход кажется довольно чистым.