Skip to content

Handling Currency in Rails

So I recently ran into a situation where I had to start actually working with dollar amounts. I think that was pretty obvious given my last post about formatting currency in JavaScript. With the UI figured out, I was trying to deal with getting the amounts into the server.

We all (hopefully) know you should always use integers to do your currency calculations. But users like to have dollars and cents to work with. Somewhere is going to live some code that handles that conversion. One post I found gave the following solution: add a before_filter to go through and convert anything that looked like it might be a currency amount:

def filter_units (input)
 if [Array, Hash, HashWithIndifferentAccess].include?(input.class)
  input.each do |key, value|
   #recurse through the data structure
   input[key] = self.filter_units(value)
 #match the string format for a major unit
 elsif not input.nil? and input.match(/^\d+\.\d\d)$/)
  #convert to a minor unit integer
  (input.to_f * 100.0).to_i
  #return the value unchanged

No offense John, but that is a terrible way of dealing with it. #1. I couldn’t even get the code to work, it gave all kinds of errors. #2. What if you have another field the contains a float, e.g. tax_percent or weight_in_lbs, which aren’t currency, but could match the format above? #3. What about when a user decides to put in 9.5 instead of 9.50, or include a dollar sign themselves ($9.50)? Finally, this still leaves you having to deal the conversion to a float by hand when it comes time to display the amount.

Here was my solution. I just added some virtual attributes to my models:

class Subscription < ActiveRecord::Base
  def price_dollars
    (self.price / 100).round
  def price_dollars=(price)
    self.price = (price.to_f * 100).to_i

*Poof!* No cumbersome code! But the above quickly becomes painful when you have several attributes, especially when they're spread across models. So extracted the above into a plugin, which I, with a complete lack of creativity, named CurrencyMagic.

class Subscription < ActiveRecord::Base
  currency_magic :dollars, :price, :cost, :sales_price, :etc

Now, I'm not in love with the plugin idea, but I wanted to have a way to test the code and share it across projects, so that's what I did. I originally made it a module that could be included, so there's really nothing more than re-organizing the code for it to work outside ActiveRecord, though I imagine that would diminish it's value somewhat.

Anywho, there you go, my solution to converting dollars to cents and back in Rails.

Posted in Rails, Ruby.

Tagged with , , , , , .

One Response

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. DarkFox says

    You should NEVER use floats for storing currency, unless you feel like spending a week searching for 35 cents that got lost somewhere (Yes, this happened), because float is only approximate. Use Decimal, always.

Some HTML is OK

or, reply to this post via trackback.