Coins

Dan Dennis

Don't Use Floats and Use the Ruby Money Gem to Represent Currencies

We often have to manage monetary values in our applications. Guess what? There’s a terrific open source solution in the Ruby community that is much better than rolling your own.

Instead of…

…using Floats or BigDecimals to represent money:

# In your migration
add_column :products, :price, :decimal

class Product < ApplicationModel
  def price_to_s
    "$ #{price.round(2).to_s("F")} USD"
  end
end

product.price = 5
#=> 0.5e1
product.price_to_s
#=> "$ 5.0 USD"

Use…

…the Ruby money gem, or in Rails, the money-rails gem:

# In your migration
add_monetize :products, :price

class Product < ApplicationModel
  monetize :price_cents
end

product.price = Money.from_amount(5, "USD")
#=> #<Money fractional:500 currency:USD>
product.price.format
#=> "$5.00"

Why?

Firstly, never use a floating point implementation to represent your currency values. Floats can introduce rounding errors due to their underlying representaion inside a computer. Just do not do this.

Decimals solve that issue to an extent as they behave in a more intuitive (and money-like) manner.

The money gem provides additional benefits as well as enforcing the well-worn recommendations for underlying data structures. It provides a simple, yet sophisticated, battle-tested, “value object” pattern—like all the best gems—for monetary amounts and currencies.

It has a sophisticated implementation of #format that works with the standard Ruby internationalisation (i18n) backend to properly (and flexibly) display monetary amounts as strings.

You can also easily convert currencies using the built-in currency exchange functionality, for which you can provide your own rates or link to a number of regularly updated currency rate services.

Why not?

You might want to code your own your ‘money’ representation if your application is operating in a more detailed financial modelling world. If you are calculating fractional monetary amounts, the money gem may not have the levels of sophistication you require.

Last updated on November 15th, 2021