Float
(Ruby) and FLOAT
(MySQL) are not suited for calculating or storing money amounts. You need to understand the following two notes or you have no business implementing invoices or do any kind of arithmetic in Ruby:Float
, it is very easy for Float
values to creep back into your code. Whenever you mix Floats
with BigDecimals
, the result will be a Float
. A common mistake is to properly do all the arithmetic using BigDecimals
, and then use a Float
constant like VAT_RATE = 0.19
to calculate the VAT rate. That constant should be defined as VAT_RATE = BigDecimal('0.19')
instead.before_save
or before_validation
callback to sum up item totals and store that value in an attribute, you need to skip those items that are #marked_for_destruction?
. Otherwise you will include items that have been ticked for deletion in a nested form. See ActiveRecord: When aggregating nested children, always exclude children marked for destruction.DECIMAL
column rather than FLOAT
column for the item's unit price.Item
model:Invoice
model like this:VAT_RATE
constant is a BigDecimal
, not a Float
.totals
which returns net, vat and gross totals in a single hash. Code that calls your invoice usually requires all these values together (e. g. to print an invoice), so we don't want to go through our items multiple times.Invoice
model changes like this: