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?
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 BigDecimal
s 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
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
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.
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.
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.
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
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.
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))
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.
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
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!
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
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 jakoBigDecimal
, który rozwiązuje wiele problemów.-
precision
iscale
należy dostosować, w zależności od tego, co reprezentujeszJeśli pracujesz z otrzymywaniem i wysyłaniem płatności,
precision: 8
iscale: 2
daje ci999,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 options
z 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
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