I\'m trying to use the money gem to handle currency in my app but I\'m running into a strange error. This is what I have in my \"record\" model:
composed_of
EDIT: Added Bonus at the end of the answer
Well, your question was interesting to me so I decided to try myself.
This works properly:
1) Product migration:
create_table :products do |t|
t.string :name
t.integer :cents, :default => 0
t.string :currency
t.timestamps
end
2) Product model
class Product < ActiveRecord::Base
attr_accessible :name, :cents, :currency
composed_of :price,
:class_name => "Money",
:mapping => [%w(cents cents), %w(currency currency_as_string)],
:constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
:converter => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }
end
3) Form:
<%= form_for(@product) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :cents %>
<%= f.text_field :cents %>
<%= f.label :currency %>
<%= f.select(:currency,all_currencies(Money::Currency::TABLE), {:include_blank => 'Select a Currency'}) %>
<%= f.submit %>
<% end %>
4) Products Helper (handmade):
module ProductsHelper
def major_currencies(hash)
hash.inject([]) do |array, (id, attributes)|
priority = attributes[:priority]
if priority && priority < 10
array ||= []
array << [attributes[:name], attributes[:iso_code]]
end
array
end
end
def all_currencies(hash)
hash.inject([]) do |array, (id, attributes)|
array ||= []
array << [attributes[:name], attributes[:iso_code]]
array
end
end
end
If you want to add currency exchange rates:
1) Your gemfile
gem 'json' #important, was not set as a dependency, so I add it manually
gem 'google_currency'
2) Initializer
create money.rb in you initializers folder and put this inside:
require 'money'
require 'money/bank/google_currency'
Money.default_bank = Money::Bank::GoogleCurrency.new
reboot your server
3) Play!
Wherever you are, you can exchange the money.
Product.first.price.exchange_to('USD')
Display with nice rendering:
Product.first.price.format(:symbol => true)