通貨/お金を処理する最良の方法は何ですか?
-
06-07-2019 - |
質問
非常に基本的なショッピングカートシステムに取り組んでいます。
integer
型の列 price
を持つテーブル items
があります。
ユーロとセントの両方を含む価格のビューで価格値を表示するのに問題があります。 Railsフレームワークで通貨を処理することに関して明らかな何かを見逃していますか?
解決
データベースで DECIMAL
タイプを使用することをお勧めします。移行では、次のようにします。
# 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
Railsでは、:decimal
タイプは BigDecimal
として返されます。これは価格計算に最適です。
整数の使用を主張する場合は、どこでも BigDecimal
との間で手動で変換する必要があり、これはおそらく苦痛になります。
mclが指摘したように、価格を印刷するには、次を使用します。
number_to_currency(price, :unit => "€")
#=> €1,234.01
他のヒント
composed_of
(ValueObjectパターンを使用したActiveRecordの一部)とMoney gemを活用する、優れたシンプルなアプローチです
必要になります
- Money gem (バージョン4.1.0)
- モデル、たとえば
Product
- モデル(およびデータベース)の
integer
列。たとえば、:price
product.rb
ファイルにこれを記述します:
class Product > ActiveRecord::Base
composed_of :price,
:class_name => 'Money',
:mapping => %w(price cents),
:converter => Proc.new { |value| Money.new(value) }
# ...
得られるもの:
- 追加の変更を行わなければ、すべてのフォームにドルとセントが表示されますが、内部表現はまだセントです。フォームは、「$ 12,034.95」などの値を受け入れます。変換してください。モデルにハンドラや属性を追加したり、ビューにヘルパーを追加したりする必要はありません。
-
product.price =" $ 12.00"
は自動的にMoneyクラスに変換されます -
product.price.to_s
は10進形式の数値(" 1234.00")を表示します -
product.price.format
は、通貨に対して適切にフォーマットされた文字列を表示します - セント(ペニーが必要な支払いゲートウェイに)を送信する必要がある場合、
product.price.cents.to_s
- 無料の通貨変換
通貨を処理する一般的な方法は、小数型を使用することです。 「Railsを使用したアジャイルWeb開発」の簡単な例を次に示します。
add_column :products, :price, :decimal, :precision => 8, :scale => 2
これにより、-999,999.99から999,999.99までの価格を処理できます
def validate
errors.add(:price, "should be at least 0.01") if price.nil? || price < 0.01
end
値の健全性チェックを行います。
money-rails gem を使用します。それはあなたのモデルのお金と通貨をうまく処理し、価格をフォーマットするためのたくさんのヘルパーも持っています。
Postgresを使用している場合(そして2017年になりましたので)、:money
列のタイプを試してください。
add_column :products, :price, :money, default: 0
仮想属性(改訂済み(有料)Railscastへのリンク)を使用して、price_in_centsを整数列を作成し、製品モデルに仮想属性price_in_dollarsをゲッターおよびセッターとして追加します。
# 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
出典: RailsCasts#016:仮想属性 :仮想属性は、データベースに直接マップしないフォームフィールドを追加するためのクリーンな方法です。ここでは、検証、関連付けなどの処理方法を示します。
間違いなく整数。
>そして、BigDecimalが技術的に存在していても、 1.5
はRubyで純粋なフロートを提供します。
誰かがSequelを使用している場合、移行は次のようになります。
add_column :products, :price, "decimal(8,2)"
どういうわけか、Sequelは:precisionと:scaleを無視します
(Sequelバージョン:sequel(3.39.0、3.38.0))
この方法で使用しています:
number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")
もちろん、通貨記号、精度、形式などは各通貨によって異なります。
number_to_currency
(標準のRails 4ビューヘルパー)にいくつかのオプションを渡すことができます:
number_to_currency(12.0, :precision => 2)
# => "$12.00"
による投稿 基礎となるAPIはすべてセントを使用してお金を表していましたが、それを変更したくありませんでした。また、私は大金を使って仕事をしていませんでした。だから私はこれをヘルパーメソッドに入れました:
sprintf("%03d", amount).insert(-3, ".")
整数を少なくとも3桁の文字列に変換し(必要に応じて先行ゼロを追加)、最後の2桁の前に小数点を挿入します。 Float
は使用しません。そこから、ユースケースに適した通貨記号を追加できます。
それは間違いなく迅速で汚れていますが、時にはそれで十分です!
Ruby&amp;のシンプルなコードレール
<%= number_to_currency(1234567890.50) %>
OUT PUT => $1,234,567,890.50
ほんの少しの更新と、RoR開発の意欲的な後輩/初心者向けのすべての回答のまとまり。説明のために必ずここに来ます。
お金を扱う
# 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
いくつかのポイント:
-
:decimal
は、多くの問題を解決するBigDecimal
として使用されます。 -
precision
およびscale
は、表現する内容に応じて調整する必要があります-
支払いの受け取りと送信を行う場合、
precision:8
およびscale:2
により、最高額として999,999.99
が得られます、90%のケースで問題ありません。 -
プロパティまたは希少車の値を表す必要がある場合は、より高い
precision
を使用する必要があります。 -
座標(経度と緯度)を使用する場合は、より高い
scale
が必要になります。
-
移行を生成する方法
上記のコンテンツを使用して移行を生成するには、ターミナルで実行します:
bin/rails g migration AddPriceToItems price:decimal{8-2}
または
bin/rails g migration AddPriceToItems 'price:decimal{5,2}'
こので説明されているとおりブログ投稿。
通貨のフォーマット
KISS 余分なライブラリをさようならし、組み込みのヘルパーを使用します。 @molfおよび@facundofariasが推奨するように、 number_to_currency
を使用します。
Railsコンソールで number_to_currency
ヘルパーを操作するには、ヘルパーにアクセスするために ActiveSupport
の NumberHelper
クラスに呼び出しを送信します。
例:
ActiveSupport::NumberHelper.number_to_currency(2_500_000.61, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
次の出力を提供します
2500000,61€
number_to_currency の他のオプション
を確認します。ヘルパー。
配置場所
アプリケーションヘルパーに配置して、ビュー内で任意の量で使用できます。
module ApplicationHelper
def format_currency(amount)
number_to_currency(amount, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
end
end
または、インスタンスメソッドとして Item
モデルに配置し、価格をフォーマットする必要がある場所(ビューまたはヘルパー)で呼び出すことができます。
class Item < ActiveRecord::Base
def format_price
number_to_currency(price, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
end
end
そして、コントローラー内で number_to_currency
を使用する例(払い戻しを表すために使用される negative_format
オプションに注意してください)
def refund_information
amount_formatted =
ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
{
# ...
amount_formatted: amount_formatted,
# ...
}
end