Class: RuboCop::Cop::DevDoc::Migration::AmountColumnInCents

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/dev_doc/migration/amount_column_in_cents.rb

Overview

Monetary columns must be stored as integer cents with an _in_cents suffix.

Rationale

Storing monetary values as floats or decimals introduces floating-point precision issues. The safe approach is to store values as integer cents and convert to dollars only in user-facing forms and displays.

This cop is heuristic: it matches column names whose last segment is a known monetary word (configurable via MonetaryNames). Extend the list in your .rubocop.yml if your domain uses different names.


t.float :amount
t.decimal :price
add_column :orders, :total, :decimal

✔️
t.integer :amount_in_cents
t.integer :price_in_cents
add_column :orders, :total_in_cents, :integer

To extend the monetary names list:

DevDoc/Migration/AmountColumnInCents:
Enabled: true
MonetaryNames:
  - amount
  - price
  - balance
  - cost
  - fee
  - total
  - subtotal
  - discount
  - tax
  - revenue   # custom addition

Examples:

# bad
t.float :amount
t.decimal :price
add_column :orders, :total, :decimal

# good
t.integer :amount_in_cents
t.integer :price_in_cents
add_column :orders, :total_in_cents, :integer

Constant Summary collapse

DEFAULT_MONETARY_NAMES =
%w[amount price balance cost fee total subtotal discount tax].freeze
MSG =
'Store monetary values as integer cents — ' \
'rename `%<name>s` to `%<name>s_in_cents` and use `t.integer`.'.freeze
COLUMN_METHODS =
%i[float decimal integer].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/rubocop/cop/dev_doc/migration/amount_column_in_cents.rb', line 60

def on_send(node)
  col_name_node = column_name_node(node)
  return unless col_name_node&.sym_type?

  col_name = col_name_node.value.to_s
  return if col_name.end_with?('_in_cents')
  return unless monetary_suffix?(col_name)

  add_offense(col_name_node, message: format(MSG, name: col_name))
end