2010-05-04 8 views
5

Estoy tratando de validar una cantidad de dinero utilizando una expresión regular: ^[0-9]+\.[0-9]{2}$precisión de coma flotante en Ruby on validaciones rieles modelo

Esto funciona bien, pero cada vez que un usuario envía el formulario y la cantidad de dinero termina en 0 (cero), ruby ​​(¿o rieles?) corta el valor de 0. Entonces 500.00 se convierte en 500.0, lo que daña la validación de expresiones regulares.

¿Hay alguna forma de que ruby ​​/ rails guarde el formato ingresado por el usuario, independientemente de los ceros finales?

+1

¿Alguna razón por la que no utiliza 'validates_numericality_of' en lugar de una expresión regular? –

+0

¿Cómo usaré 'validates_numericality_of' para asegurar que 500.001 fallaría? Solo quiero, específicamente formateado, '[cualquier número de dígitos 0 a 9]. [2 de cualquier dígito 0 a 9]' - usando así 'validates_format_of: amount,: with =>/^ [0-9] + \.[0-9] {2} $ /,: mensaje => "debe contener dólares y centavos, separados por un período" ' –

Respuesta

8

Supongo que su cantidad en dólares es de tipo decimal. Por lo tanto, cualquier valor que el usuario ingrese en el campo se envía desde la cadena al tipo apropiado antes de guardarlo en la base de datos. La validación se aplica a los valores ya convertidos a tipos numéricos, por lo que Regex no es realmente un filtro de validación adecuado en su caso.

Usted tiene dos posibilidades para resolver esto, sin embargo:

  1. Uso validates_numericality_of. De esta forma, deja la conversión completamente en Rails y simplemente verifica si la cantidad está dentro de un rango determinado.
  2. Utilice el método validate_each y codifique su lógica de validación usted mismo (por ejemplo, verifique si el valor tiene más de 2 dígitos decimales).
  3. Validar la attribute before it's been typecasted:

Esto es especialmente útil en situaciones de validación donde el usuario podría suministrar una cadena para un campo entero y desea mostrar la cadena original de nuevo en un error mensaje. Acceder al atributo normalmente encasillaría la cadena en 0, que no es lo que desea.

Así, en su caso, debe ser capaz de utilizar:

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

Nótese, sin embargo, que los usuarios podrían encontrar aburrido de seguir sus reglas rígidas para el ingreso (I realmente preferiría poder tipo 500 en su lugar 500.00, por ejemplo), y que en algunos lugares el período no es un separador decimal (si alguna vez planea internacionalizar su aplicación).

+0

¿Podría ... ': amount_before_type_cast' ... dar como resultado la inserción de" 500.0 "en la base de datos? Aprobar la validación es una cosa, pero los gerentes aún podrían sacar el registro de pago y leerían "500.0" a pesar de la correcta entrada de los usuarios. Ver respuesta a Arkku, la rigidez/rigor es por solicitud. –

+0

Usted (y especialmente los gerentes) no deberían preocuparse por cómo se almacena un valor en la base de datos. Es un número, debe almacenarse como un número (sin embargo, hay numerosos formatos numéricos en diferentes bases de datos). El número de decimales debe especificarse solo al formatear la salida, es decir, en la vista de la base de datos. –

+1

Ah, y, por favor, nunca _nunca_ consideren cambiar ese tipo de columna DB a cadena. –

2

En general, si desea "recordar" la precisión decimal de un valor de coma flotante, debe usar un tipo decimal, no un flotante binario.

Por otro lado, no estoy seguro de por qué desea forzar la representación de cadena de una manera tan estricta ... ¿Qué hay de aceptar cualquier número y formatearlo, por ejemplo, con. number_to_currency?

+0

La rigidez fue solicitada por el CFO del departamento de contabilidad para el cual esta aplicación es. Él realmente quiere que la gente escriba exactamente en este formato en el formulario. '@payment.amount = number_to_currency (@ payment.amount,: unit => '') 'before' @ payment.save' (a través del controlador) está produciendo los mismos resultados ... ¿Lo estoy haciendo mal? –

+0

Me temo que estás ... number_to_currency es para fines de presentación, es decir, para usar al dar salida a la cantidad en la vista. Por cierto, si las reglas son tan rígidas que podrías considerar hacer alguna validación del lado del cliente, estoy seguro de que hay muchas soluciones basadas en jQuery y prototipos para esto. –

0

Por lo general, con dinero, lo mejor es almacenarlo como un número entero en centavos (500 centavos es $ 5,00). Yo uso el Money gem para manejar esto.

Cuestiones relacionadas