私は非常に基本的なショッピングカートシステムに取り組んでいます。
タイプitems
の列price
を持つテーブルinteger
があります。
ユーロとセントの両方を含む価格の私の見解では、価格の値を表示できません。 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
sとの間で手動で変換しなければならないでしょう、これはおそらくただ痛みになるでしょう。
Mclが指摘したように、価格を表示するには、次のようにします。
number_to_currency(price, :unit => "€")
#=> €1,234.01
これはcomposed_of
(ActiveRecordの一部であり、ValueObjectパターンを使用)とMoney gemを利用した、巧妙で単純なアプローチです。
あなたは必要になるでしょう
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) }
# ...
あなたが得るもの:
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:仮想属性 :仮想属性はフォームを追加するためのきれいな方法ですデータベースに直接マップしないフィールド。ここでは、検証、関連付けなどを処理する方法を説明します。
誰かがSequelを使用している場合、移行は次のようになります。
add_column :products, :price, "decimal(8,2)"
どういうわけかSequelは:precisionと:scaleを無視します
(続編:続編(3.39.0、3.38.0))
間違いなく 整数 。
そして、BigDecimalが技術的に存在していても、1.5
はRubyであなたに純粋なFloatを与えるでしょう。
私はこの方法でそれを使っています:
number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")
もちろん、通貨記号、精度、フォーマットなどは各通貨によって異なります。
私の基になるAPIはすべてお金を表すためにセントを使用していました、そして私はそれを変更したくありませんでした。また、私は多額のお金を使って仕事をしていませんでした。だから私はちょうどこれをヘルパーメソッドに入れます:
sprintf("%03d", amount).insert(-3, ".")
整数を3桁以上の文字列に変換し(必要に応じて先行ゼロを追加し)、最後の2桁の前に小数点を挿入します。Float
は使用しません。そこから、ユースケースに適した通貨記号を追加できます。
それは間違いなく素早く汚いですが、時にはそれでいいのです!
number_to_currency
(標準のRails 4ビューヘルパー)にいくつかのオプションを渡すことができます。
number_to_currency(12.0, :precision => 2)
# => "$12.00"
投稿者として Dylan Markow
Ruby&Rails用の簡単なコード
<%= number_to_currency(1234567890.50) %>
OUT PUT => $1,234,567,890.50
RoR開発の意欲的な後輩/初心者のためのちょっとした更新とすべての答えのまとまり。
@molfが示唆しているように(そして私の会社がお金を扱うときの黄金の基準として使うもの)、DBにお金を保存するために: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
いくつかのポイント:
: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}'
これで説明されているように blog 投稿。
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 ヘルパーの他のoptions
を確認してください。
あなたはそれをアプリケーションヘルパーに入れて、ビューの中でどんな量でもそれを使うことができます。
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
そして、私がcontrrolerの中で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