48 votes

Rails JSON Serialization of Decimal ajoute citations

J'utilise par défaut la sérialisation JSON pour un modèle qui a un certain nombre de décimal entier et les attributs. Un exemple de résultat est:

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

Remarquer l'ajout de guillemets autour de la valeur de "notation". Cela provoque la désérialisation de la bibliothèque que j'utilise de manière incorrecte les considérer comme des chaînes de caractères (au lieu de décimales). Peut Rails être configuré pour ne pas utiliser les guillemets pour toutes les décimales?

Edit:

Je suis sur des Rails 3.0.7 et Ruby 1.9.2 si cela fait une différence.

Edit:

Terminal:

rails g model user rating:decimal
rake db:migrate

Console:

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

44voto

Marcel Jackwerth Points 20632

Le seul moyen "sans danger" à la main décimales de la langue A vers la langue B est d'utiliser une Chaîne de caractères. Si votre json contient "rating": 98.79999999999999 il sera probablement converti 98.79999999999998 par votre moteur d'exécution JavaScript.

Voir BigDecimal as_json de la documentation:

Un BigDecimal serait naturellement représenté comme un JSON nombre. La plupart des bibliothèques, cependant, l'analyse non-entier JSON numéros directement flotteurs. Les Clients l'utilisation de ces bibliothèques obtenir en général un mauvais numéro et pas de moyen de récupérer d'autres qu'à la main l'inspection de la chaîne avec le JSON le code lui-même.

C'est pourquoi une chaîne JSON est retourné. Le JSON littérale n'est pas numérique, mais si l'autre extrémité sait par contrat que les données qui est censé être un BigDecimal, il a encore la chance de post-processus de la chaîne et obtenir le la valeur réelle.

Si vous voulez forcer les Rails de ne pas citer ces, vous pourriez singe-patch BigDecimal (voir les Rails de la 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

28voto

toxaq Points 2427

Ce qui a changé pour les Rails 4.0 qui a l'option ActiveSupport.encode_big_decimal_as_string , de sorte que vous pouvez spécifier votre BigDecimal la sérialisation de préférence. Voir l'émission de 6033

En attendant, si vous êtes à l'aise avec les arguments mis de l'avant dans 6033 et que vous exécutez un Rails de version inférieure à 4.0, vous pouvez monkey patch BigDecimal comme ci-dessous

require 'bigdecimal'

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

Cela a résolu mes problèmes avec RABL le pompage des chaînes pour les montants stockés en tant que BigDecimal.

10voto

alexzg Points 109

si vous utilisez ActiveModel::Serializer vous pouvez également utiliser to'f pour forcer la conversion de type Décimale à Float. qui wil aussi couper la citation pour vous!

donc dans votre classe de serializer objet. faire``

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X