2012-06-18 18 views
5

Aquí es lo que estoy usando en mi modelo:¿Cómo elimino los signos de dólar de un valor antes de la validación en Rails?

before_validation :strip_dollar_sign 

validates :amount_due, 
      :format => { :with => /^\d+??(?:\.\d{0,2})?$/ }, 
      :numericality => {:greater_than => 0} 

private 

def strip_dollar_sign 
    self.amount_due = self.amount_due.to_s.tr!('$,','').to_f 
end 

Si me quedo la línea de la función strip_dollar_sign a mano en la consola de Rails consigo exactamente lo que quiero (es decir, $ 400 termina como 400,0), pero cuando Utilizo el formulario real en mi aplicación, el valor siempre termina en 0.0. ¿Alguien capta lo que estoy haciendo mal?

+3

El dinero no se debe almacenar como flotantes, sino como decimal en la base de datos y BigDecimal en ruby. Los flotantes pueden tener errores de redondeo que pueden causar resultados inesperados. – DGM

Respuesta

14

tres problemas aquí:

  • como señaló Stefan en his answer, es posible que desee quitar el , en su llamada tr!, aunque esto no afectará a la sustitución de un $.

  • Está utilizando tr! y está utilizando su valor de retorno de forma incorrecta. tr! (junto con la mayoría de las variantes de método de Ruby !) devuelve nil si no se realizaron cambios en la cadena original. Dado que nil.to_f es 0.0, es por eso que está obteniendo eso (o tal vez no, consulte a continuación). En su lugar, debe usar tr.

  • rieles convierte automáticamente los argumentos de asignación para el tipo correcto para la columna de la base de datos asociada con él, por lo que incluso antes de la validación de su valor se está convirtiendo en un flotador, y es "$400".to_f0.0, y eso es lo que ve a su devolución de llamada. La solución es reemplazar amount_due= en lugar de utilizar una devolución de llamada:

    def amount_due=(value) 
        value = value.to_s.tr('$', '').to_f 
        write_attribute(:amount_due, value) 
    end 
    
+1

En realidad, la coma en la llamada 'tr' está bien (aunque probablemente también sea indeseada):' "$ 500" .tr ("$,", '') '. Para citar los documentos: "Devuelve una copia de str con los caracteres de from_str reemplazados por los caracteres correspondientes en to_str. Si to_str es más corto que from_str, se rellena con su último carácter para mantener la correspondencia". –

+0

@MichaelKohl Buen punto, editado para notar que no afecta el reemplazo del '$', aunque puede ser no deseado ya que una coma es un delimitador en algunos locales (más el OP parece haber implicado en la respuesta de Stefan que fue un error). –

+0

Creo que estás haciendo algo aquí, pero algo más todavía está roto. Si voy a la consola y ejecuto 'amount_due =" $ 400 "' y luego 'amount_due.to_s.tr ('$', '') .to_f' la salida es' 400.0'. Pero si creo un objeto y trato de asignar el mismo '$ 400' al valor' .amount_due', igual obtengo '0.0'. – richrad

3

Hay una coma después de $ por lo que está eliminando $, en lugar de .

+0

¡Buena captura! Pero todavía escupe 0.0. – richrad

-2

Yo recomiendo hacer esto en javascript. Rails parece hacer algo de magia con los helpers de formularios que convertirán cualquier valor no numérico en un campo respaldado por un tipo de base de datos numérica en 0.0. Estúpido, lo sé.

+0

OP está pidiendo soluciones en Rails (como puede ver las etiquetas) por lo que JS no es una respuesta a su pregunta. –

Cuestiones relacionadas