1
votes

I have an Order model with unit_price, discount_price, final_price etc.. All are integer fields in postgres db. Currently its rounding amount to the next integer and saves that. But now I found that this is not a good approach as it might cause some errors/issues in future. So I planned to save money values in penny by doing(USD*100) but when displaying shows it in GBP by writing some helpers.

But I found this gem now money-rails which could do what I want. I am trying to wrap my head around this gem,but I cant really figure out some conventions used here also not sure its suitable for my purpose

My default currency is GBP.

I can see that this gem uses the convention _cents by default

monetize :price_cents #from docs

Above assume a db column price_cents. Here why we should use cents as a static column? Whats the purpose of that? Other than being explicit any other uses here?

If its for a purpose like for cents it automatically look for USD, if penny looks for GBP & soforth... then for each currency our app supports we will endup creating new db columns like price_penny, price_cent etc.. which is not that great if there are lot of currencies. Or can I use a generic name here like price_smallest and use this regardless of currecy type? Also

I cant figure out the exact usecase here properly. Could someone shed some light into this topic?

Note: My app doesn't have plans for supporting other currencies now. But could be added in future. So good to consider that now I think..

1
It appears to be for inference purposes e.g monetize :price with the default configuration will assume price_cents and price_currency. You can see "_cents" is the default postfix for the amount columns in the default configuration.engineersmnky
Since the default currency is 'USD' and a cent is the smallest denomination of the US monetary system it makes the most sense for this to be the postfix. That being said it is not required to be cents but one does not need to separate by the currency type this is simply just a convention and can be configured as you see fit as the "_cents" column or whatever you choose to call it will contain the subunit value based on the Currency. e.g. cents has a subunit_to_unit of 100 because there are 100 cents in a wholeengineersmnky
This Spec Test makes it pretty clear where you can see in USD the cents is expected to be 2,000,000 but in CLP (which has a subunit_to_unit of 1) the "cents" is expected to be the same as the amount 20,000engineersmnky
@engineersmnky Thankyou for making it clear. Please provide as an answer so I can accept.Abhilash

1 Answers

1
votes

So you need to remove the columns unit_price, discount_price, final_price from the table orders. And add them back correctly with add_monetize.

create a new migration file that looks like this:

class FixPricesInOrders < ActiveRecord::Migration[5.0]
  def change
    # Remove Columns
    remove_column :orders, :unit_price
    remove_column :orders, :discount_price
    remove_column :orders, :final_price
    # Add money
    add_monetize :orders, :unit_price
    add_monetize :orders, :discount_price
    add_monetize :orders, :final_price
  end
end

From https://github.com/RubyMoney/money-rails

"Due to the addition of the money column type for PostgreSQL in Rails 4.2, you will need to use add_monetize instead of add_money column."

Then make sure you add the following to app/models/order.rb

monetize :unit_price
monetize :discount_price
monetize :final_price