/ / Rails JSON Serializacja dziesiętna dodaje cudzysłowy - ruby ​​na szynach

Rails JSON Serialization of Decimal dodaje Quotes - ruby-on-rails

Używam domyślnej serializacji JSON dla modelu, który ma wiele atrybutów dziesiętnych i całkowitych. Przykładowy wynik to:

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

Zwróć uwagę na dodanie cudzysłowów wokół wartości"ocena". Powoduje to, że biblioteka deserializacji, której używam, niepoprawnie traktuje je jako łańcuchy (zamiast miejsc po przecinku). Czy w Railsach nie można używać cudzysłowów dla wszystkich miejsc po przecinku?

Edytować:

Jestem na Railsach 3.0.7 i Ruby 1.9.2, jeśli to robi różnicę.

Edytować:

Terminal:

rails g model user rating:decimal
rake db:migrate

Konsola:

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

Odpowiedzi:

27 dla odpowiedzi nr 1

Zmieniło się to w Railsach 4.0, które mają tę opcję ActiveSupport.encode_big_decimal_as_string dzięki czemu możesz określić swoje preferencje serializacji BigDecimal. Patrz numer 6033

W międzyczasie, jeśli „czujesz się swobodnie z argumentami przedstawionymi w 6033 i używasz wersji Rails niższej niż 4.0, możesz małpować łatkę BigDecimal jak poniżej.

require "bigdecimal"

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

To rozwiązało moje problemy z wypompowywaniem przez RABL ciągów dla kwot dolara przechowywanych jako BigDecimal.


39 dla odpowiedzi nr 2

Jedynym „bezpiecznym” sposobem przekazywania miejsc po przecinku z języka A ​​na język B jest użycie ciągu znaków. Jeśli twój Json zawiera "rating": 98.79999999999999 prawdopodobnie zostanie przekonwertowany na 98.79999999999998 przez środowisko wykonawcze JavaScript.

Widzieć BigDecimal as_json dokumentacja:

BigDecimal byłby naturalnie reprezentowany jakoNumer JSON. Większość biblioteki parsują jednak wartości całkowite Numery JSON bezpośrednio jako liczby zmiennoprzecinkowe. Klienci korzystający z tych bibliotek to zrobiliby dostać ogólnie zły numer i nie sposób na odzyskanie inny niż ręcznie sprawdzanie ciągu za pomocą JSON sam kod.

Dlatego zwracany jest ciąg JSON. Literał JSON nie jest liczbowy, ale jeśli drugi koniec wie na podstawie umowy że dane mają być BigDecimal, wciąż ma szansę po przetworzeniu ciągu i pobierz prawdziwa wartość.

Jeśli chcesz zmusić Railsy do nie cytowania ich, możesz załatać małpa BigDecimal (patrz Railsy źródło).

# 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

9 dla odpowiedzi nr 3

jeśli używasz ActiveModel :: Serializer, możesz także użyć to_f, aby wymusić konwersję z typu dziesiętnego na zmiennoprzecinkowy. że również wyciąć wycenę dla Ciebie!

więc w klasie obiektów serializujących obiekty. robić

def rating
self.rating.to_f
end

0 dla odpowiedzi nr 4

Z Railsami 5 encode_big_decimal_as_string nie działa (było przestarzałe, więc nie ma w tym nic dziwnego).

Jeśli dodasz jbuilder do swojej aplikacji

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

Następnie po prostu utwórz widok jsona, w którym przecinek dziesiętny jest ustawiany na liczbę zmiennoprzecinkową tylko dla widoku.

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

Działa to dla mnie dobrze - trochę więcej pracy (ponieważ musisz zmapować swój model do jbuildera), ale takie podejście wydaje się dość czyste.