2012-06-18 3 views
5

Hier ist, was in meinem Modell Ich verwende:Wie entferne ich Dollarzeichen von einem Wert vor der Validierung in 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 

Wenn ich die Linie von der strip_dollar_sign Funktion von Hand in der Rails-Konsole ich genau das bekommen, laufen, was ich will (dh $ 400 endet als 400,0), aber wenn Ich benutze das eigentliche Formular in meiner App, der Wert endet immer bei 0.0. Wer fängt was ich falsch mache?

+3

Geld sollte nicht als Gleitkommazahl gespeichert werden, sondern als Dezimalzahl in der Datenbank und BigDecimal in Ruby. Floats können Rundungsfehler aufweisen, die zu unerwarteten Ergebnissen führen können. – DGM

Antwort

14

Drei Probleme hier:

  • Wie in his answer von Stefan wies darauf hin, können Sie die , in Ihrem tr! Anruf zu entfernen, wenn es nicht um den Ersatz eines $ beeinflussen.

  • Sie verwenden tr! und verwenden den Rückgabewert falsch. tr! (zusammen mit den meisten Methodenmethoden von Ruby !) gibt nil zurück, wenn keine Änderungen an der ursprünglichen Zeichenfolge vorgenommen wurden. Seit nil.to_f ist 0.0, deshalb bekommen Sie das (oder vielleicht nicht, siehe unten). Sie sollten stattdessen tr verwenden.

  • Rails konvertiert automatisch Zuordnung Argumente in den richtigen Typ für die Datenbankspalte mit ihm verbunden, so dass auch vor der Validierung Ihr Wert auf einen Schwimmer wird, umgewandelt und "$400".to_f ist 0.0, und das ist, was Ihr Rückruf sieht. Die Lösung ist amount_due= anstatt mit einem Rückruf außer Kraft zu setzen:

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

Eigentlich ist das Komma im 'tr' Aufruf gut (wenn auch wahrscheinlich unerwünscht):' "$ 500" .tr ("$,", '') '. Um die Dokumente zu zitieren: "Gibt eine Kopie von str zurück, wobei die Zeichen in from_str durch die entsprechenden Zeichen in to_str ersetzt werden. Wenn to_str kürzer ist als from_str, wird es mit seinem letzten Zeichen aufgefüllt, um die Korrespondenz zu erhalten." –

+0

@MichaelKohl Guter Punkt, bearbeitet, um zu bemerken, dass er die Ersetzung des '$' nicht beeinflusst, obwohl es immer noch unerwünscht sein kann, da ein Komma in einigen Gebietsschemata ein Trennzeichen ist (plus das OP scheint in Stefans Antwort impliziert zu haben Das war ein Fehler). –

+0

Ich denke, Sie sind hier auf etwas, aber etwas anderes ist immer noch gebrochen. Wenn ich in die Konsole gehe und 'amount_due =" $ 400 "' und dann 'amount_due.to_.tr ('$', '') .to_f" starte, ist die Ausgabe '400.0'. Aber wenn ich ein Objekt erstelle und versuche, dem '.amount_due'-Wert die gleiche '$ 400' zuzuweisen, bekomme ich immer noch' 0.0'. – richrad

3

Es gibt ein Komma nach $, also entfernen Sie $, statt $.

+0

Guter Fang! Aber es spuckt immer noch 0,0 aus. – richrad

-2

ich dies in Javascript empfehlen tun. Rails scheint mit Formularhilfen, die alle nicht-numerischen Werte in einem Feld, das von einem numerischen Datenbanktyp unterstützt wird, in 0.0 konvertiert werden, eine gewisse Magie zu erzeugen. Dumm, ich weiß.

+0

OP fragt nach Lösungen in Rails (wie Sie die Tags sehen können), also JS keine Antwort auf seine Frage. –

Verwandte Themen