2010-05-04 5 views
5

Je suis en train de valider un montant en dollars en utilisant une expression régulière: ^[0-9]+\.[0-9]{2}$précision en virgule flottante en rubis sur le modèle des rails de validation

Cela fonctionne très bien, mais à chaque fois qu'un utilisateur soumet le formulaire et le montant en dollars se termine par 0 (zéro), rubis (ou rails?) côtelettes le 0 off. Donc 500.00 se transforme en 500.0 échouant ainsi à la validation de l'expression rationnelle.

Est-il possible de faire en sorte que ruby ​​/ rails conserve le format entré par l'utilisateur, indépendamment des zéros de fin?

+1

Une raison pour laquelle vous n'utilisez pas 'validates_numericality_of' à la place d'une regex? –

+0

Comment utiliser 'validates_numericality_of' pour m'assurer que 500.001 échouerait? Je veux seulement, spécifiquement formaté, '[n'importe quel nombre de 0 à 9 chiffres]. [2 de 0 à 9 chiffres]' - utilisant ainsi 'validates_format_of: amount,: with =>/^ [0-9] + \.[0-9] {2} $ /,: message => "doit contenir des dollars et des cents, séparés par une période" ' –

Répondre

8

Je présume que votre montant en dollars est de type décimal. Ainsi, toute valeur entrée par l'utilisateur dans le champ est transtypée de la chaîne vers le type approprié avant d'être enregistrée dans la base de données. La validation s'applique aux valeurs déjà converties en types numériques, donc regex n'est pas vraiment un filtre de validation approprié dans votre cas.

Vous avez deux possibilités pour résoudre ce problème, cependant:

  1. Utilisez validates_numericality_of. De cette façon, vous laissez la conversion complètement à Rails, et vérifiez simplement si le montant est dans une plage donnée.
  2. Utilisez la méthode validate_each et codez vous-même votre logique de validation (par exemple, vérifiez si la valeur comporte plus de 2 chiffres décimaux).
  3. Valider la attribute before it's been typecasted:

Ceci est particulièrement utile dans situations de validation où l'utilisateur pourrait fournir une chaîne pour un entier champ et que vous souhaitez afficher la chaîne d'origine retour dans une erreur message. En accédant à l'attribut , la chaîne serait normalement transposée en 0, ce qui n'est pas ce que vous voulez.

Ainsi, dans votre cas, vous devriez pouvoir utiliser:

validates_format_of :amount_before_type_cast, :with => /^[0-9]+\.[0-9]{2}$/, :message => "must contain dollars and cents, seperated by a period" 

Notez, cependant, que les utilisateurs pourraient trouver fastidieux de suivre vos règles d'entrée rigides (je préférerais vraiment être en mesure de tapez 500 au lieu de 500.00, par exemple), et que dans certaines régions, la période n'est pas un séparateur décimal (si vous envisagez d'internationaliser votre application).

+0

Est-ce que ... ': amount_before_type_cast' ... entraînerait toujours l'insertion de" 500.0 "dans la base de données? Passer la validation est une chose, mais les gestionnaires pourraient encore remonter le dossier de paiement et ils liraient "500.0" malgré les entrées correctes des utilisateurs? Voir la réponse à Arkku, la rigidité/rigueur est sur demande. –

+0

Vous (et surtout les gestionnaires) ne devriez pas vous préoccuper de la façon dont une valeur est stockée dans la base de données. C'est un nombre, il devrait être stocké sous forme de nombre (cependant, il existe de nombreux formats numériques dans différentes bases de données). Le nombre de décimales doit être spécifié uniquement lors du formatage de la sortie, c'est-à-dire dans la vue de votre base de données. –

+1

Oh, et, s'il vous plaît, jamais _ever_ envisager de changer ce type de colonne DB en chaîne. –

2

En général, si vous souhaitez vous "souvenir" de la précision décimale d'une valeur à virgule flottante, vous devez utiliser un type décimal, pas un flottant binaire. Par contre, je ne suis pas certain de vouloir forcer la représentation des chaînes de manière aussi stricte ... Que diriez-vous d'accepter n'importe quel nombre et de le formater avec, par ex. number_to_currency?

+0

La rigidité a été demandée par le directeur financier de la comptabilité pour laquelle cette application est destinée. Il veut que les gens tapent exactement dans ce format dans le formulaire. '@payment.amount = number_to_currency (@ payment.amount,: unit => '') 'avant que' @ payment.save' (via le contrôleur) produise les mêmes résultats ... est-ce que je le fais mal? –

+0

Je crains que vous ne soyez ... number_to_currency est destiné à des fins de présentation, c'est-à-dire à utiliser lors de la sortie du montant dans la vue. BTW, si les règles sont si rigides que vous pourriez envisager de faire une validation côté client, je suis sûr qu'il y a beaucoup de solutions basées sur jQuery et prototype pour cela. –

0

Habituellement avec de l'argent, il est préférable de le stocker sous forme d'entier en cents (500 cents est de 5,00 $). J'utilise le Money gem pour gérer cela.

Questions connexes