Frage

Ich arbeite an einer sehr einfachen Warenkorb-system.

Ich habe eine Tabelle items mit einer Spalte price Typ integer.

Ich habe Probleme mit dem Preis Wert, meine Ansichten für die Preise, die umfassen sowohl Euro und Cent.Bin ich etwas fehlt offensichtlich so weit wie handling Währung in der Rails-framework ist betroffen?

War es hilfreich?

Lösung

Sie werden wahrscheinlich eine DECIMAL Art in Ihrer Datenbank verwenden möchten. In Ihrer Migration, etwas tun, wie folgt aus:

# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, :precision => 8, :scale => 2

In Rails, der :decimal Typ wird als BigDecimal zurückgegeben, die für die Preiskalkulation groß ist.

Wenn Sie sich mit ganzen Zahlen bestehen, werden Sie manuell überall und von BigDecimals umwandeln müssen, was wahrscheinlich nur ein Schmerz geworden.

Wie von mcl, um den Preis zu drucken:

number_to_currency(price, :unit => "€")
#=> €1,234.01

Andere Tipps

Hier ist ein schöner, einfacher Ansatz, den composed_of (Teil von Active, mit dem ValueObject Muster) und das Geld gem

nutzt

Sie müssen

  • Die Geld gem (Version 4.1.0)
  • Ein Modell, zum Beispiel Product
  • Eine integer Spalte in Ihrem Modell (und Datenbank), zum Beispiel :price

Schreiben Sie dies in Ihrer product.rb-Datei:

class Product > ActiveRecord::Base

  composed_of :price,
              :class_name => 'Money',
              :mapping => %w(price cents),
              :converter => Proc.new { |value| Money.new(value) }
  # ...

Was Sie erhalten:

  • Ohne zusätzliche Änderungen, werden alle Ihre Formen zeigen Dollar und Cent, aber die interne Darstellung ist nach wie vor nur Cent. Die Formulare werden Werte wie „$ 12,034.95“ akzeptieren und konvertiert es für dich. Es gibt keine Notwendigkeit, zusätzliche Handler hinzuzufügen oder Attribute zu Ihrem Modell oder Helfer in der Ansicht.
  • product.price = "$12.00" wandelt automatisch in dem Geld Klasse
  • product.price.to_s zeigt eine Dezimalzahl formatiert Nummer ( "1234,00")
  • product.price.format zeigt eine korrekt formatierte Zeichenfolge für die Währung
  • Wenn Sie Cent senden (zu einem Payment-Gateway, das ein paar Cent will), product.price.cents.to_s
  • Währungsumrechnung kostenlos

Gängige Praxis Währung für den Umgang mit dezimal Typen verwenden. Hier ist ein einfaches Beispiel von "Agile Web Development mit Rails"

add_column :products, :price, :decimal, :precision => 8, :scale => 2 

Damit können Sie Preise von -999,999.99 zu 999,999.99
zu handhaben Sie können auch eine Validierung in Ihrem Artikel wie

enthalten sein sollen
def validate 
  errors.add(:price, "should be at least 0.01") if price.nil? || price < 0.01 
end 

zur Vernunft Überprüfen Sie Ihre Werte.

Verwenden Sie Geld-Schienen gem . Es behandelt schön Geld und Währungen in Ihrem Modell und hat auch eine Reihe von Helfern Ihre Preise zu formatieren.

Wenn Sie Postgres (und da wir im Jahr 2017 nun) möchten Sie vielleicht, um Ihre :money Spalte Typ eine versuchen.

add_column :products, :price, :money, default: 0

Virtuelle Attribute (Link zur revised (gegen Entgelt) Railscast) Sie price_in_cents in einem speichern integer-Spalte und fügen Sie ein virtuelles Attribut price_in_dollars in Ihrem Produktmodell als Getter und Setter.

# Add a price_in_cents integer column
$ rails g migration add_price_in_cents_to_products price_in_cents:integer

# Use virtual attributes in your Product model
# app/models/product.rb

def price_in_dollars
  price_in_cents.to_d/100 if price_in_cents
end

def price_in_dollars=(dollars)
  self.price_in_cents = dollars.to_d*100 if dollars.present?
end

Quelle: Railscasts # 016: Virtuelle Attribute : virtuelle Attribute sind eine saubere Art und Weise Formularfelder hinzufügen, die Karte nicht direkt auf die Datenbank. Hier zeige ich, wie Validierungen zu handhaben, Verbände und vieles mehr.

Auf jeden Fall ganzen Zahlen .

Und obwohl BigDecimal technisch existiert 1.5 werden Sie noch eine reine Float in Ruby geben.

Wenn jemand Sequel mit der Migration etwas aussehen würde:

add_column :products, :price, "decimal(8,2)"

irgendwie Sequel ignoriert: Präzision und: Skala

(Sequel Version: Fortsetzung (3.39.0, 3.38.0))

Ich benutze es auf diese Weise:

number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")

Natürlich, die das Währungssymbol, Präzision, Format und so weiter auf jeder Währung abhängt.

Sie können einige Optionen übergeben number_to_currency (ein Standard-Rails 4 View Helfer):

number_to_currency(12.0, :precision => 2)
# => "$12.00"

Wie geschrieben von Dylan Markow

Meine zugrunde liegenden APIs waren Cents alle mit Geld zu repräsentieren, und ich wollte nicht, das ändern. Auch arbeite ich mit großen Mengen an Geld. Also ich habe dies nur in einer Hilfsmethode:

sprintf("%03d", amount).insert(-3, ".")

Das wandelt die ganze Zahl in einen String mit mindestens drei Ziffern (Hinzufügen von führenden Nullen, falls erforderlich), dann fügt ein Komma vor den letzten beiden Ziffern, nie ein Float verwenden. Von dort können Sie addieren, was Währungssymbole für Ihren Anwendungsfall geeignet sind.

Es ist auf jeden Fall schnell und schmutzig, aber manchmal das ist gut so!

Einfacher Code für Ruby & Rails

<%= number_to_currency(1234567890.50) %>

OUT PUT => $1,234,567,890.50

Nur ein kleines Update und ein Zusammenhalt aller Antworten für einige aufstrebende Junioren / Anfänger in RoR Entwicklung, die sicherlich kommen hier einige Erklärungen.

Arbeiten mit Geld

Mit :decimal zu speichern Geld in der DB, wie @molf vorgeschlagen (und was mein Unternehmen verwendet als Goldstandard, wenn sie mit Geld arbeiten).

# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, precision: 8, scale: 2

Ein paar Punkte:

  • :decimal verwendet werden, wie BigDecimal wird, die eine Menge Probleme löst.

  • precision und scale sollte so eingestellt werden, je nachdem, was Sie repräsentieren

    • Wenn Sie mit Empfangen und Senden von Zahlungen arbeiten, precision: 8 und scale: 2 geben Sie als höchste Menge 999,999.99, die in 90% der Fälle in Ordnung ist.

    • Wenn Sie den Wert einer Immobilie oder eines seltenen Auto darstellen müssen, sollten Sie eine höhere precision verwenden.

    • Wenn Sie mit den Koordinaten (Längen- und Breitengrad) arbeiten, werden Sie sicherlich brauchen eine höhere scale.

Wie eine Migration erzeugen

Um die Migration mit dem obigen Inhalt zu erzeugen, in Terminal ausführen:

bin/rails g migration AddPriceToItems price:decimal{8-2}

oder

bin/rails g migration AddPriceToItems 'price:decimal{5,2}'

, wie in diesem Blog Post.

Währungs Formatierung

KISS die zusätzliche Bibliotheken auf Wiedersehen und verwenden eingebaute Helfer. Verwenden Sie number_to_currency als @molf und @facundofarias vorgeschlagen.

mit number_to_currency Helfern zu spielen, in Rails-Konsole, einen Aufruf an die ActiveSupport Klasse, um die NumberHelper zu senden, um die Helfer zu gelangen.

Zum Beispiel:

ActiveSupport::NumberHelper.number_to_currency(2_500_000.61, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")

gibt die folgende Ausgabe

2500000,61€

Überprüfen Sie die anderen options von number_to_currency Helfer.

Wo es setzen

Sie können es in einer Anwendung Helfer setzen und es in Ansichten für jede Menge verwenden.

module ApplicationHelper    
  def format_currency(amount)
    number_to_currency(amount, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end

Oder Sie können es im Item Modell als eine Instanz Methode setzen, und es nennen, wo Sie den Preis zu formatieren (in Ansichten oder Helfer).

class Item < ActiveRecord::Base
  def format_price
    number_to_currency(price, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end

Und ein Beispiel, wie ich die number_to_currency in einem contrroler verwenden (die negative_format Option bemerken, verwendet Erstattungen darzustellen)

def refund_information
  amount_formatted = 
    ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
  {
    # ...
    amount_formatted: amount_formatted,
    # ...
  }
end
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top