Question
I'm building a basic shopping cart system in Ruby on Rails.
I have an items table with a price column stored as an integer.
I'm having trouble displaying prices correctly in my views when the value should include both euros and cents. Is there a standard or recommended way to handle currency values in Rails? Am I missing something obvious about how money should be stored and displayed?
Short Answer
By the end of this page, you'll understand the standard Rails approach to handling money: store values in the smallest currency unit (such as cents) using integers, then format them for display in views. You'll also learn why this is safer than using floating-point numbers, how to convert values correctly, and how this pattern is used in real Rails applications.
Concept
Money should be handled carefully in software because even tiny rounding errors can cause incorrect totals, taxes, or payment values.
In Rails applications, a very common approach is:
- Store money as an integer in the smallest unit of the currency
- Euros -> store cents
- Dollars -> store cents
- Pounds -> store pence
- Format the integer for display when showing it to users
For example:
1999in the database means €19.99500means €5.0049means €0.49
This matters because floating-point numbers like 19.99 are not always stored exactly in binary. That can lead to surprising errors when adding or comparing values.
For example, in many languages:
0.1 + 0.2
# => 0.30000000000000004
That is fine for scientific calculations, but it is dangerous for money.
So the core idea is:
- Store exact values as integers
- Convert to a human-friendly currency string in the view
- Keep calculations in integers whenever possible
Rails helps with formatting through helpers such as number_to_currency.
Mental Model
Think of money like counting coins in a jar.
Instead of writing "19.99 euros" inside the database, you count the smallest pieces:
- 19 euros and 99 cents
- total = 1999 cents
The database stores the exact coin count.
Later, when you want to show the amount to a user, Rails acts like a cashier printing a receipt:
1999becomes€19.99
So:
- Database value = exact internal amount
- View output = readable currency format
This separation makes your code safer and easier to maintain.
Syntax and Examples
A common Rails pattern is to store an integer column such as price_cents instead of price.
Model data example
Suppose your items table stores this:
Item.create(name: "Book", price_cents: 1299)
That means the book costs €12.99.
Displaying the value in a view
Rails provides the number_to_currency helper:
<%= number_to_currency(@item.price_cents / 100.0, unit: "€") %>
Output:
€12.99
Better model method
Instead of repeating conversion logic in views, define a method in the model:
class Item < ApplicationRecord
def price_in_euros
price_cents / 100.0
end
end
Step by Step Execution
Consider this Ruby code:
price_cents = 1299
price_euros = price_cents / 100.0
formatted = ActionController::Base.helpers.number_to_currency(price_euros, unit: "€")
puts formatted
Step-by-step
-
price_cents = 1299- The internal stored value is
1299 - This means 1299 cents
- The internal stored value is
-
price_euros = price_cents / 100.01299 / 100.0becomes12.99- Using
100.0is important because it produces a decimal result
-
number_to_currency(price_euros, unit: "€")- Rails formats the number as currency
- It adds the currency symbol and correct decimal places
-
puts formatted- Output is:
Real World Use Cases
Handling money this way appears in many real applications:
-
Shopping carts
- Product prices are stored in cents
- Cart totals are calculated exactly
-
Subscriptions
- Monthly plans might be stored as
999for €9.99
- Monthly plans might be stored as
-
Invoices
- Line items, tax, and totals must be precise
-
Payment gateways
- Many APIs such as Stripe expect amounts in the smallest unit
- Example: charge
2500for €25.00
-
Discount systems
- A coupon can subtract
500cents instead of5.00
- A coupon can subtract
-
Reports and exports
- Internal reports can keep exact integer values
- UI and PDFs can format them for human reading
This pattern is popular because it reduces ambiguity and prevents rounding surprises.
Real Codebase Usage
In real Rails codebases, developers usually combine integer storage with a few clean design patterns.
Clear column naming
Use names like:
price_centssubtotal_centstax_centstotal_cents
This avoids confusion about the unit.
Model helper methods
Developers often wrap conversion logic inside model methods:
class Item < ApplicationRecord
def price
price_cents / 100.0
end
end
That keeps views simpler.
Guard clauses for missing values
class Item < ApplicationRecord
def price
return 0 if price_cents.nil?
price_cents / 100.0
end
Common Mistakes
1. Storing money as float
Broken approach:
# bad
price = 19.99
Why it is a problem:
- floats can introduce rounding errors
- totals may become inaccurate
Better:
price_cents = 1999
2. Using a vague column name
Broken approach:
# unclear
price
Why it is a problem:
- other developers may assume
pricemeans euros, not cents
Better:
price_cents
3. Dividing integers incorrectly
Broken code:
price_cents = 1299
price_cents / 100
# => 12
Problem:
- cents are lost
Better:
Comparisons
| Approach | Example stored value | Good for money? | Notes |
|---|---|---|---|
| Integer smallest unit | 1999 | Yes | Best common choice for carts and payments |
| Float | 19.99 | No | Can introduce rounding errors |
| Decimal / numeric | 19.99 | Sometimes | Better than float, but integer cents is often simpler for app logic |
Integer cents vs decimal columns
| Option | Advantage | Disadvantage |
|---|---|---|
| Integer cents | Exact, simple, matches many payment APIs |
Cheat Sheet
Recommended pattern
- Store money as an integer in the smallest unit
- Use names like
price_cents - Convert only when displaying to users
- Use Rails helpers for formatting
Example database meaning
100-> €1.00250-> €2.501999-> €19.99
View formatting
<%= number_to_currency(@item.price_cents / 100.0, unit: "€") %>
Model method
def price_in_euros
price_cents / 100.0
end
Validation
validates :price_cents, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
Good rules
- Use integer cents internally
- Keep calculations in cents
- Format at the edge of the app, usually in the view
- Prefer clear names like
total_cents
FAQ
Why should I store money as cents in Rails?
Because integers are exact. This avoids floating-point rounding errors and makes totals more reliable.
Can I use a decimal column instead of an integer?
Yes, a decimal column is safer than a float. But storing cents as integers is often simpler and very common in shopping carts and payment systems.
How do I display 1999 as €19.99 in Rails?
Divide by 100.0 and use number_to_currency:
<%= number_to_currency(1999 / 100.0, unit: "€") %>
Should the database column be called price or price_cents?
price_cents is better because it clearly tells you what unit is stored.
Why is my division removing the cents?
You may be doing integer division, such as 1299 / 100. Use 1299 / 100.0 instead.
Does Rails have built-in money support?
Rails provides formatting helpers like number_to_currency, but it does not automatically solve all money storage rules. You still need a good storage strategy.
When should I use a gem for money handling?
Mini Project
Description
Build a tiny Rails-style product pricing example that stores prices in cents and displays them in euros. This demonstrates the standard pattern used in shopping carts: exact integer storage for calculations, and formatted output for the user.
Goal
Create a product model with cent-based pricing, validate the value, and display formatted euro prices cleanly.
Requirements
- Create a product object with a
price_centsvalue stored as an integer. - Add a method that converts cents to euros.
- Validate that
price_centsis a non-negative integer. - Display the formatted price using a Rails currency helper.
- Calculate a total for multiple quantities using cents first, then format the result.
Keep learning
Related questions
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.
Convert a Unix Timestamp to Ruby DateTime
Learn how to convert Unix timestamps to Ruby DateTime and Time objects, with examples, differences, pitfalls, and practical Ruby usage.