image by 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"

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


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

# In your migration
add_monetize :products, :price

class Product < ApplicationModel
  monetize :price_cents

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


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 by @andycroll

An email newsletter, with one Ruby/Rails technique delivered with a ‘why?’ and a ‘how?’ every two weeks. It’s deliberately brief, focussed & opinionated.