Class: RuboCop::Cop::DevDoc::Migration::AmountColumnInCents
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Migration::AmountColumnInCents
- 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
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 |