DEV Community

Cover image for How to handle a price with Ruby-on-Rails
Vorachith Phoubandith
Vorachith Phoubandith

Posted on

How to handle a price with Ruby-on-Rails

You surely ever needed to add a price column in a table of your database. But what type to select for the column price? A beginner will try with a float and meet trouble to display the price value.

Use the type Decimal !

Let's create a Book table with title, description and price columns. I put the validations aside, it is not the subject of this tiny article.

rails g model Book title:string author: string price:decimal{8,2}
Enter fullscreen mode Exit fullscreen mode

After making the usual rails db:migrate, launch 'rails c' in the terminal so you can try to create an entry in your database. You can use the next code for convenience :

book = Book.new(
  title: 'La nuit des temps',
  author: 'Barjavel',
  price: 10.99)
book.save
Enter fullscreen mode Exit fullscreen mode

No errors right? But your surely see price value like that :

price: 0.1099e2
Enter fullscreen mode Exit fullscreen mode

To display the price with decimal formatted number, you can use .to_s, so we get :

book.price.to_s # 10.99
Enter fullscreen mode Exit fullscreen mode

Done!

Discussion (5)

Collapse
phawk profile image
Pete Hawkins

Great advice! I have seen a lot saying to always store prices as cents, but I've run into more issues with this approach than yours, particularly when it comes to supporting multiple currencies like JPY which don't have decimals units.

Collapse
songta17 profile image
Vorachith Phoubandith Author

Thanks ! Small precision that we need to know when we use this advice: during the model creation and depending of the need, we can adapt the first digit :

  • price:decimal{3,2} # value between. -9.99 and 9.99
  • price:decimal{4,2} # value between. -99.99 and 99.99
  • price:decimal{5,2} # value between. -999.99 and 999.99 etc.
Collapse
yarotheslav profile image
Yaroslav Shmarov

I disagree.

As suggested by the below gems, "Represents monetary values as integers, in cents. This avoids floating point rounding errors." github.com/RubyMoney/money, github.com/RubyMoney/money-rails

Moreover, as Stripe docs suggests,
expect amounts to be provided in a currency’s smallest unit. For example, to charge 10 USD, provide an amount value of 1000 (that is, 1000 cents).
For zero-decimal currencies, still provide amounts as an integer but without multiplying by 100. For example, to charge ¥500, provide an amount value of 500.

stripe.com/docs/currencies#zero-de...

Integer is the way to go. An CRM that I've been maintaining for 6 years now runs on quite a lot money calculations, and the numbers add up just well :)

Collapse
songta17 profile image
Vorachith Phoubandith Author

Thanks for your contribution! Really appreciate your point ;)

Collapse
devrafaeldelgad profile image
Rafael C. Delgado

It's easy if you use,

123456789.to_formatted_s(:currency) => $ 123,456,789.00