Leveraging Rails' Money Type

You have a Rails application and need to persist some data through a form which has a JavaScript money mask.

Here in Brazil for instance, we format money this way: R$ 1.000,90.

Given this is a string and we need to save as decimal or integer, we have to convert.

class String
  # Convert a money string ('R$ 10.000,00') to float (10000.0)
  def clean_money
    self.gsub(/[^\d,]/, '').gsub(',', '.').strip.to_f
  end
end

The clean_money above solves the problem, however, we always have to call it before set our data in the model (not that DRY).

Looking for a better way to do it I found two good solutions:

  • Create your column as money type (Rails 4.2+)
  • Use the new attributes API (Rails 5+)

Both solutions only work if you are using PostgreSQL.

Column as money type

class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.money :price
    end
  end
end

Attributes API

class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.decimal :price
    end
  end
end
class Product < ApplicationRecord
  attribute :price, :money # will behave like money type
end

You just need it, really.

Then we can pass strings straight to our models:

Product.create(price: "R$ 50,80")
puts Product.last.price
# 50.8

Product.create(price: "$ 10,000.80")
puts Product.last.price
# 10000.8

See you.

Written on December 13, 2016

Share: