Multi-currency support: Money + Currency class improvements #553
Reference in New Issue
Block a user
Delete Branch "money-and-currency-class"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This PR is a precursor to #543, which was growing too big and tackling too many things at once.
Overview
Below are some explanations of changes and sample usage for documentation purposes.
Money lib
Adds
Money,Money::Currency, andMoney::Arithmetictolibas these represent generic concepts that could apply to any app that deals with money.Moneypackages up all the information required to represent a monetary value (amount, currency)Money::Currencystores information about all global currencies and can provide a list of these throughMoney::Currency.allorMoney::Currency.popularMoney::Arithmeticallows us to add, subtract, multiply, divide, and compare monetary values without any special syntax. In other words, we can doMoney.new(0) == Money.new(0)orMoney.new(100) > Money.new(5)Why not
moneyandmoney-rails?There are two main reasons I decided to go with a custom implementation:
moneyandmoney-railsgems are somewhat opinionated about a project's money storage strategy. Throughout most of its API, it assumes that money is being stored in minor currency units. Our project does not do that. We store inDecimal{19,4}, which was chosen to make the data a lot more intuitive (1 less layer of indirection). Furthermore, themoney-railsgem integrates at the model level (with migration helpers), which as we saw with a first attempt at using it, caused unnecessary confusion for new contributors.Monetizable Concern + Form Helper
In an attempt to keep things simple and intuitive, as an alternative to the
money-railsstrategy that "magically" turns fields likeAccount.balanceintoMoneyinstances, I've created aMonetizableconcern with a straightforward API:This unobtrusively adds a field called
balance_money, which returnsMoney.new(balance, currency).Furthermore, I've created a form helper with the following API:
f.money_fieldwill readamount_moneyand create an:amountand:currencyinput that is updated on submission.The overall goal here is to give the developer flexibility when working with money and making it explicit when a field deals with money and when it doesn't.