What is the best method of handling currency/money?

Here's a fine, simple approach that leverages composed_of (part of ActiveRecord, using the ValueObject pattern) and the Money gem

You'll need

  • The Money gem (version 4.1.0)
  • A model, for example Product
  • An integer column in your model (and database), for example :price

Write this in your product.rb file:

class Product > ActiveRecord::Base

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

What you'll get:

  • Without any extra changes, all of your forms will show dollars and cents, but the internal representation is still just cents. The forms will accept values like "$12,034.95" and convert it for you. There's no need to add extra handlers or attributes to your model, or helpers in your view.
  • product.price = "$12.00" automatically converts to the Money class
  • product.price.to_s displays a decimal formatted number ("1234.00")
  • product.price.format displays a properly formatted string for the currency
  • If you need to send cents (to a payment gateway that wants pennies), product.price.cents.to_s
  • Currency conversion for free

You'll probably want to use a DECIMAL type in your database. In your migration, do something like this:

# 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, the :decimal type is returned as BigDecimal, which is great for price calculation.

If you insist on using integers, you will have to manually convert to and from BigDecimals everywhere, which will probably just become a pain.

As pointed out by mcl, to print the price, use:

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