RubyMoney money-rails for storing monetary values in Rails
Integration of RubyMoney - Money with Rails
At a glance
- What is it?
- RubyMoney money-rails connects the money gem to Rails models, migrations, validations, and Rack applications. It suits applications that store minor currency units such as cents and need a Money object at the model boundary.
- Who is it for?
- Adopt money-rails when monetary data is represented by integer minor units and the application needs Money-aware model attributes, migrations, and validations. Do not adopt it merely because a project already uses money, since the gem adds a Rails-specific persistence layer.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 24 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why money-rails belongs in a Rails persistence layer
Money arithmetic carries more state than a plain integer. A Money object includes a monetary amount and a currency, so code that receives only cents has to depend on an external convention if it wants to format, compare, or convert that value correctly. money-rails addresses that gap by connecting the RubyMoney money gem to Rails.
The intended users are Ruby and Rails applications whose database records contain monetary values in minor units. The README uses a Product model with a `price_cents` column as its primary example. Once `monetize :price_cents` is declared, the record receives a `price` attribute containing a Money object. The stored representation remains based on the database column, while application code can use the attribute as Money.
This is narrower than a general currency conversion service. money-rails does not introduce exchange rates, payment processing, or a ledger by itself. Its documented scope is the boundary between Rails persistence and the money gem. That distinction matters for project selection: applications handling payment execution need additional systems, while applications storing and manipulating prices can evaluate this integration on its model and migration behavior.
How monetize maps Rails fields to Money values
For ActiveRecord, the `monetize` macro derives a Money attribute name by removing the `_cents` suffix from the field name. Thus, `price_cents` produces `price`. This is a naming convention, not a change to the database column. The database continues to store the integer value, and the generated model attribute wraps it in Money.
A model can select a different attribute name with the `as` option:
monetize :discount_subunit, as: "discount"The `discount` attribute then wraps the value from `discount_subunit`. The README also documents monetizing calculated methods rather than database columns. In the Transaction example, `price_cents`, `tax_cents`, and `total_cents` are monetized, while `total_cents` is calculated from the first two values. The generated `total` method consequently returns Money.
Validation behavior is configurable at several levels. A field can use normal numericality options, use `subunit_numericality` for the stored minor-unit value, disable validation entirely with `disable_validation: true`, or disable only one validation by setting an option such as `numericality: false`. This flexibility is useful, but it also means schema and model declarations should be reviewed together. A valid Money-facing attribute is not enough if its persisted subunit value has unsuitable bounds.
Installing money-rails and monetizing a Product
For a Rails application, the documented installation is to add the gem to the application Gemfile:
bundle add money-railsAlternatively, install the gem directly:
gem install money-railsGenerate the money configuration initializer with:
bin/rails generate money_rails:initializerThe initializer is the documented place to define the default currency and other configuration parameters. After installation, a first ActiveRecord use requires a monetary column. The following example declares an integer-backed price field on a Product model:
class Product < ActiveRecord::Base
monetize :price_cents
endBased on the README, the Product object should then expose `price` as a Money object. The underlying `price_cents` field remains available, and the README says the Money attribute supports comparisons and conversions. The generated initializer is also relevant to this first use because monetized fields use the Money library's global default currency unless configured otherwise.
For a Rack application without Rails, the README calls `MoneyRails::Hooks.init` during initialization. It does not provide a more complete standalone Rack setup in the displayed documentation, so that single initialization call is the documented starting point.
ActiveRecord migrations for price, currency, and nil values
money-rails includes migration helpers intended to keep the storage design consistent. The `add_monetize` helper can add amount and currency columns, and it can be customized inside a `MoneyRails.configure` block. The README recommends configuring the helper for the application's common case and then reusing it across migrations.
A price field can be added directly to a migration:
class MonetizeProduct < ActiveRecord::Migration
def change
add_monetize :products, :price
end
endThe helper is reversible and can therefore be used inside `change`. When separate `up` and `down` methods are used, the documentation identifies `remove_monetize` as the corresponding removal helper. A `change_table` form is also available:
def change
change_table :products do |t|
t.monetize :price
end
endBy default, the generated currency field has a default of USD. The README says to override this by changing `default_currency` in the initializer and then running migrations. This is a migration concern, not merely a runtime setting.
Nullable monetary fields require explicit schema and model choices:
monetize :optional_price_cents, allow_nil: trueThe corresponding migration can apply nullability to amount, currency, or both:
def change
add_monetize :products,
:optional_price,
amount: { null: true, default: nil },
currency: { null: true, default: nil }
endPer-column options take precedence over top-level `null: true`. This is important because a field that accepts a nil Money value must also have a database representation that permits nil. The README shows that both `optional_price` and `optional_price_cents` then return nil after a blank assignment and save.
Currency configuration, ranges, and Mongoid storage
Every monetized conversion uses the Money library's global default currency by default. The generated configuration can set it explicitly:
MoneyRails.configure do |config|
config.default_currency = :usd
endThe displayed README ends before its complete currency-option list, so it confirms the configuration key but does not establish all supported currency strategies. In particular, it does not document whether a particular deployment supports a specific per-record currency selection. Applications that depend on that behavior need to consult the rest of the project documentation before adoption.
Integer range is another concrete boundary. The README cites -2147483648 to +2147483647 for Postgres and recommends changing a column to `bigint` with limit 8 when larger amounts are expected:
def change
change_column :products, :price_cents, :integer, limit: 8
endFor Mongoid, money-rails takes a different route. Instead of the ActiveRecord `monetize` macro, Money is supplied as a field type. The documented model declares `field :price, type: Money`. The README shows Money assignment before saving and a stored money hash containing `cents` and `currency_iso` after saving. Normal Mongoid field options, including `index` and `default`, remain available. This support makes the project useful beyond ActiveRecord, although the examples do not establish feature parity between every Mongoid option and every ActiveRecord option.
Practical limits, maintenance signals, and a direct alternative
The clearest limitation is the amount of schema convention involved. A Rails application adopting money-rails must coordinate a Money attribute, an integer amount field, a currency field where applicable, nullable columns, default currency configuration, and validation options. Getting only the model declaration right can still leave a migration default, integer range, or nullability policy inconsistent.
The project is not archived, and the last push was on 2026-09-29. That is a recent maintenance signal, but the repository has no GitHub releases. The absence of releases means the repository record does not provide a release cadence or a named upgrade path through GitHub release notes. Upgrade planning must therefore account for the fact that changes may be visible through the repository and `CHANGELOG.md` rather than a published GitHub release series. The repository uses the MIT license, so the source is permissively licensed, although compatibility with an application's dependencies and obligations remains a separate review.
A real alternative is to use the money gem without Rails integration. money-rails explicitly builds on money, but the `monetize` macro, migration helpers, Rails initializer, generated model attributes, and Rack hook are supplied by the integration layer. An application that does not use ActiveRecord or Mongoid and manages its own persistence can keep Money objects at its service boundary while handling conversion itself. money-rails is the better fit when schema-level Rails integration is desired. Plain money is the better fit when database mapping belongs outside the model integration.
Reviewing money-rails before adding it to an application
The adoption decision should begin with the database schema rather than the Money API. Check whether each amount is stored as an integer in minor units, whether the column name follows the `_cents` convention or has an explicit `as` name, and whether the value can exceed the documented integer range. Then inspect the currency columns and their defaults. The migration helper's USD default and the initializer's global currency are separate concerns, and changing the initializer alone does not retroactively change existing migrations.
Validation deserves equal attention. Decide which attributes represent persisted values, which represent calculated methods, and whether each one should allow nil. Use `numericality` or `subunit_numericality` only where the intended unit matches the bound. A `greater_than_or_equal_to: 10000` applied to the Money-facing amount and the same bound applied to a subunit column do not describe the same range.
For Mongoid users, verify the actual `Money` field behavior against the application's Mongoid version and indexing requirements. For Rack users, confirm where `MoneyRails::Hooks.init` runs in the application lifecycle. For all integrations, inspect the dependency files and `CHANGELOG.md` when planning an upgrade, because the repository has no GitHub releases. On the available evidence, money-rails is appropriate for Rails applications that want Money-aware attributes backed by integer persistence, but it is not a substitute for payment processing, exchange-rate management, or a custom persistence mapping that the project does not cover.
Editorial conclusion
Adopt money-rails when monetary data is represented by integer minor units and the application needs Money-aware model attributes, migrations, and validations. Do not adopt it merely because a project already uses money, since the gem adds a Rails-specific persistence layer. Verify first that your database columns, nullable fields, currency defaults, and validation rules match the conventions configured in the application.
Frequently asked questions
How do I install money-rails in a Rails application?
The README documents `bundle add money-rails` for an application Gemfile or `gem install money-rails` for a direct installation. It also documents generating the configuration file with `bin/rails generate money_rails:initializer`.
How does monetize create a Money attribute?
For an ActiveRecord column named `price_cents`, `monetize :price_cents` creates a `price` attribute containing a Money object. Use `as: "discount"` when the Money attribute should have a different name.
Can money-rails store nullable monetary fields?
Yes. Set `allow_nil: true` on the model declaration and configure the migration with nullable amount and currency options, or use top-level `null: true` to apply nullability to both columns. The README states that blank assignments can then be saved.
Does money-rails support Mongoid?
Yes. The README shows `field :price, type: Money` inside a Mongoid document and describes storage as a hash containing `cents` and `currency_iso`. Normal Mongoid field options such as `index` and `default` remain available.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rubymoney-money-rails)Was this useful?