Jaka jest najlepsza metoda obsługi waluty / pieniędzy?

Pracuję nad bardzo podstawowym systemem wózków.

Mam tabelę items, która ma kolumnę price typu integer.

Mam problem z wyświetlaniem wartości ceny w moich poglądach dla cen, które zawierają zarówno euro, jak i centy. Czy brakuje mi czegoś oczywistego, jeśli chodzi o obsługę waluty w Rails framework?

Author: the Tin Man, 2009-06-20

13 answers

Prawdopodobnie będziesz chciał użyć typu DECIMAL w swojej bazie danych. W swojej migracji zrób coś takiego:

# 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

W Rails typ :decimal jest zwracany jako BigDecimal, co jest Świetne do obliczania ceny.

Jeśli nalegasz na używanie liczb całkowitych, będziesz musiał ręcznie konwertować do iz BigDecimals wszędzie, co prawdopodobnie stanie się bólem.

Jak zauważył mcl, aby wydrukować cenę, użyj:

number_to_currency(price, :unit => "€")
#=> €1,234.01
 466
Author: molf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 12:35:14

Jest to proste podejście, które wykorzystuje composed_of (część ActiveRecord, używając wzorca ValueObject) i Money gem [11]}

Będziesz potrzebował

  • the Money gem (version 4.1.0)
  • model, na przykład Product
  • kolumna integer w twoim modelu (i bazie danych), na przykład :price

Zapisz to w pliku product.rb:

class Product > ActiveRecord::Base

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

Co dostaniesz:

  • bez żadnych dodatkowych zmian, wszystkie Twoje formularze będą Pokaż dolary i centy, ale wewnętrzna reprezentacja to nadal tylko centy. Formularze przyjmą wartości takie jak" $12,034.95 " i przekonwertują je dla Ciebie. Nie ma potrzeby dodawania dodatkowych funkcji obsługi lub atrybutów do modelu ani pomocników w widoku.
  • product.price = "$12.00" automatycznie konwertuje do klasy pieniądza
  • product.price.to_s wyświetla liczbę w formacie dziesiętnym ("1234.00")
  • product.price.format wyświetla poprawnie sformatowany ciąg znaków dla waluty
  • jeśli trzeba wysłać centów (do płatności gateway, który chce groszy), product.price.cents.to_s
  • przelicznik walut za darmo
 108
Author: Ken Mayer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 15:59:26

Powszechną praktyką obsługi waluty jest używanie typu dziesiętnego. Oto prosty przykład z "Agile Web Development with Rails"

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

To pozwoli Ci obsługiwać ceny od -999,999.99 do 999,999. 99
Możesz również dołączyć walidację do swoich elementów, takich jak

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

To sanity-Sprawdź swoje wartości.

 25
Author: alex.zherdev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 20:48:39

Użyj money-rails gem . Ładnie radzi sobie z pieniędzmi i walutami w twoim modelu, a także ma kilka pomocników do formatowania cen.

 7
Author: Troggy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-30 00:38:26

Używając Virtual Attributes(Link do revised (paid) Railscast) możesz zapisać price_in_cents w kolumnie integer i dodać wirtualny atrybut price_in_dollars w modelu produktu jako getter i 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

Źródło: RailsCasts #016: wirtualne atrybuty: wirtualne atrybuty są czystym sposobem dodawania pól formularza, które nie są mapowane bezpośrednio do bazy danych. Tutaj pokazuję, jak obsługiwać walidacje, skojarzenia i inne.

 5
Author: Thomas Klemm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-22 21:08:45

Jeśli używasz Postgres (a ponieważ jesteśmy teraz w 2017 roku), możesz spróbować ich kolumny :money type.

add_column :products, :price, :money, default: 0
 3
Author: The Whiz of Oz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-02 16:35:26

Zdecydowanie liczby całkowite .

I mimo że BigDecimal technicznie istnieje 1.5 nadal da ci czysty Float w Ruby.

 2
Author: moot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-22 20:52:19

Jeśli ktoś używa sequela migracja wyglądałaby tak:

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

Jakoś Sequel ignoruje: precision i: scale

(Wersja Sequel: sequel (3.39.0, 3.38.0))

 2
Author: jethroo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-17 10:35:51

Używam go w ten sposób:

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

Oczywiście, że symbol waluty, precyzja, format i tak dalej zależy od każdej waluty.

 2
Author: facundofarias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-17 17:34:18

Możesz przekazać niektóre opcje do number_to_currency (standardowego pomocnika widoku Rails 4):

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

As posted by Dylan Markow

 1
Author: blnc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:38

Moje podstawowe interfejsy API używały centów do reprezentowania pieniędzy i nie chciałem tego zmieniać. Nie pracowałam też z dużymi sumami pieniędzy. Więc po prostu umieściłem to w metodzie pomocniczej:

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

, który zamienia liczbę całkowitą na łańcuch z co najmniej trzema cyframi( dodając początkowe zera, jeśli to konieczne), a następnie wstawia punkt dziesiętny przed dwiema ostatnimi cyframi, nigdy nie używając Float. Stamtąd możesz dodać dowolne symbole walutowe odpowiednie do twojego przypadku użycia.

To zdecydowanie szybkie i brudne, ale czasami jest to w porządku!

 1
Author: Brent Royal-Gordon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-10 01:59:56

Prosty kod do Ruby & Rails

<%= number_to_currency(1234567890.50) %>

OUT PUT => $1,234,567,890.50
 0
Author: Dinesh Vaitage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-30 08:37:51

Mała aktualizacja i spójność wszystkich odpowiedzi dla niektórych początkujących juniorów / początkujących w rozwoju RoR, które z pewnością przyjdą tutaj po jakieś wyjaśnienia.

Praca z pieniędzmi

Użyj :decimal do przechowywania pieniędzy w DB, zgodnie z sugestią @molf (i tego, czego moja firma używa jako złotego standardu podczas pracy z pieniędzmi).

# 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

Kilka punktów:

  • :decimal będzie używany jako BigDecimal, który rozwiązuje wiele problemów.

  • precision i scale należy dostosować, w zależności od tego, co reprezentujesz

    • Jeśli pracujesz z otrzymywaniem i wysyłaniem płatności, precision: 8 i scale: 2 daje ci 999,999.99 jako najwyższą kwotę, która jest w 90% przypadków grzywna.

    • Jeśli chcesz przedstawić wartość nieruchomości lub rzadkiego samochodu, powinieneś użyć wyższej precision.

    • Jeśli pracujesz ze współrzędnymi (długość i szerokość geograficzna), na pewno potrzebujesz wyższej scale.

Jak wygenerować migrację

Aby wygenerować migrację z powyższą zawartością, uruchom w terminalu:

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

Lub

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

Jak wyjaśniono w tym blog post.

Formatowanie waluty

KISS the extra libraries goodbye and use built-in helpers. Użyj number_to_currency zgodnie z sugestiami @molf i @facundofarias.

Aby zagrać z number_to_currency helperem w konsoli Rails, wyślij wywołanie do ActiveSupport ' s NumberHelper klasa w celu uzyskania dostępu do helpera.

Na przykład:

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

Daje następujące wyjście

2500000,61€

Sprawdź pozostałe optionsz liczba_to_kwartości .

Gdzie to umieścić

Możesz umieścić go w helperze aplikacji i używać go wewnątrz widoków za dowolną kwotę.

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

Lub możesz umieścić go w modelu Item jako metodę instancji i zadzwonić tam, gdzie trzeba sformatować cenę (w widokach lub pomocnicy).

class Item < ActiveRecord::Base
  def format_price
    number_to_currency(price, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end
W przeciwieństwie do innych systemów, które nie są w pełni kompatybilne z innymi systemami, nie są w pełni kompatybilne z innymi systemami.]}
def refund_information
  amount_formatted = 
    ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
  {
    # ...
    amount_formatted: amount_formatted,
    # ...
  }
end
 0
Author: Zlatko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 14:09:13