it-swarm.com.de

Was ist die beste Methode, um mit Geld/Geld umzugehen?

Ich arbeite an einem sehr einfachen Warenkorbsystem. 

Ich habe eine Tabelle items, die eine Spalte price vom Typ integer hat. 

Ich habe Probleme, den Preis in meinen Ansichten für Preise anzuzeigen, die sowohl Euro als auch Cent enthalten. Fehle ich etwas offensichtliches, was den Umgang mit Währung im Rails-Framework angeht?

308
Barry Gallagher

Sie möchten wahrscheinlich einen DECIMAL-Typ in Ihrer Datenbank verwenden. Führen Sie in Ihrer Migration Folgendes 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 wird der :decimal-Typ als BigDecimal zurückgegeben, was sich hervorragend für die Preisberechnung eignet.

Wenn Sie darauf bestehen, Ganzzahlen zu verwenden, müssen Sie die Variable BigDecimals überall manuell konvertieren, was wahrscheinlich nur schmerzhaft wird.

Wie von mcl angegeben, verwenden Sie zum Ausdrucken des Preises:

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

Hier ist ein einfacher, einfacher Ansatz, der composed_of (Teil von ActiveRecord, unter Verwendung des ValueObject-Musters) und des Money-Gems nutzt 

Du brauchst

  • Der Money Edelstein (Version 4.1.0) 
  • Ein Modell, zum Beispiel Product
  • Eine integer-Spalte in Ihrem Modell (und Ihrer Datenbank), zum Beispiel :price

Schreiben Sie dies in Ihre 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 du bekommst:

  • Ohne zusätzliche Änderungen werden in allen Formularen Dollar und Cent angezeigt, die interne Darstellung ist jedoch immer noch nur Cent. Die Formulare akzeptieren Werte wie "$ 12.034.95" und konvertieren sie für Sie. Sie müssen Ihrem Modell keine zusätzlichen Handler oder Attribute oder Helfer in Ihrer Ansicht hinzufügen.
  • product.price = "$12.00" wird automatisch in die Money-Klasse konvertiert
  • product.price.to_s zeigt eine dezimal formatierte Zahl an ("1234.00")
  • product.price.format zeigt eine ordnungsgemäß formatierte Zeichenfolge für die Währung an
  • Wenn Sie Cents senden müssen (an ein Zahlungsgateway, das ein Pfennig möchte), product.price.cents.to_s
  • Währungsumrechnung kostenlos
111
Ken Mayer

Für die Handhabung von Währungen ist es üblich, den Dezimaltyp ..__ zu verwenden.

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

Damit können Sie mit Preisen von -999,999,99 bis 999,999,99 umgehen
Möglicherweise möchten Sie auch eine Überprüfung in Ihre Artikel einfügen, z 

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

deine Werte zu überprüfen.

25
alex.zherdev

Verwenden Sie money-Rails gem . Es kann gut mit Geld und Währungen in Ihrem Modell umgehen und hat auch eine Reihe von Helfern, um Ihre Preise zu formatieren.

7
Troggy

Virtuelle Attribute verwenden (Link zu überarbeitetem (bezahltem) Railscast) Sie können Ihre price_in_cents in einer ganzzahligen Spalte speichern und ein virtuelles Attribut price_in_dollars in Ihrem Produktmodell als Getter und Setter hinzufügen.

# 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 stellen eine saubere Methode zum Hinzufügen von Formularfeldern dar, die nicht direkt der Datenbank zugeordnet sind. Hier zeige ich, wie Validierungen, Zuordnungen und Mehr.

5
Thomas Klemm

Wenn Sie Postgres verwenden (und seit wir jetzt 2017 sind), möchten Sie vielleicht den :money-Spaltentyp ausprobieren.

add_column :products, :price, :money, default: 0
5
The Whiz of Oz

Wenn jemand Sequel verwendet, würde die Migration ungefähr so ​​aussehen: 

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

irgendwie ignoriert Sequel: Präzision und: Skalierung

(Fortsetzung Version: Fortsetzung (3.39.0, 3.38.0))

2
jethroo

Auf jeden Fall ganze Zahlen .

Und obwohl BigDecimal technisch vorhanden ist, gibt Ihnen 1.5 trotzdem einen reinen Float in Ruby.

2
moot

Ich verwende es auf diesem Weg:

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

Natürlich hängt das Währungssymbol, die Genauigkeit, das Format usw. von jeder Währung ab.

2
facundofarias

Meine zugrunde liegenden APIs verwendeten alle Cent, um Geld darzustellen, und ich wollte das nicht ändern. Ich arbeitete auch nicht mit großen Geldbeträgen. Also habe ich nur eine Hilfsmethode verwendet:

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

Dadurch wird die Ganzzahl in eine Zeichenfolge mit mindestens drei Ziffern umgewandelt (wobei ggf. führende Nullen hinzugefügt werden). Anschließend wird vor den letzten beiden Ziffern ein Dezimalpunkt eingefügt, wobei niemals eine Float verwendet wird. Von dort aus können Sie die für Ihren Anwendungsfall geeigneten Währungssymbole hinzufügen.

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

1

Sie können einige Optionen an number_to_currency (einen Standard-Helfer für View-4-Ansichten) übergeben:

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

Wie geschrieben von Dylan Markow

1
blnc

Einfacher Code für Ruby & Rails

<%= number_to_currency(1234567890.50) %>

OUT PUT => $1,234,567,890.50
0
Dinesh Vaitage

Nur ein kleines Update und eine Zusammenfassung aller Antworten für aufstrebende Junioren/Anfänger in der RoR-Entwicklung, die sicherlich zu Erläuterungen kommen werden.

Mit Geld arbeiten

Verwenden Sie :decimal, um Geld in der Datenbank zu speichern, wie @molf vorgeschlagen hat (und was mein Unternehmen als goldenen Standard verwendet, 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

Einige Punkte:

  • :decimal wird als BigDecimal verwendet, wodurch viele Probleme gelöst werden.

  • precision und scale sollten je nach Darstellung angepasst werden

    • Wenn Sie mit dem Empfangen und Senden von Zahlungen arbeiten, erhalten Sie mit precision: 8 und scale: 2999,999.99 den höchsten Betrag, was in 90% der Fälle in Ordnung ist.

    • Wenn Sie den Wert einer Immobilie oder eines seltenen Autos darstellen müssen, sollten Sie ein höheres precision verwenden.

    • Wenn Sie mit Koordinaten (Längengrad und Breitengrad) arbeiten, benötigen Sie sicherlich ein höheres scale.

So generieren Sie eine Migration

Um die Migration mit dem obigen Inhalt zu generieren, führen Sie das Terminal aus:

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

oder

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

wie in diesem Blog Post erklärt.

Währungsformatierung

KISS die zusätzlichen Bibliotheken verabschieden sich und verwenden integrierte Helfer. Verwenden Sie number_to_currency als @molf und @facundofarias vorgeschlagen.

Um mit dem number_to_currency-Helfer in der Rails-Konsole zu spielen, müssen Sie einen Anruf an die ActiveSupport-Klasse von NumberHelper senden, um auf den Helfer zuzugreifen.

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 das andere options von number_to_currency helper.

Wo soll ich hinlegen?

Sie können es in einem Anwendungshelfer ablegen und innerhalb von Ansichten für jeden beliebigen Betrag verwenden. 

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

Sie können es auch als Instanzmethode in das Modell Item einfügen und dort anrufen, wo Sie den Preis formatieren müssen (in Ansichten oder Helfern).

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 den number_to_currency in einem Steuerelement verwende (beachten Sie die negative_format-Option, die für die Rückerstattung verwendet wird).

def refund_information
  amount_formatted = 
    ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
  {
    # ...
    amount_formatted: amount_formatted,
    # ...
  }
end
0
Zlatko