money-rails 1.15.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -6
- data/LICENSE +1 -1
- data/README.md +121 -102
- data/config/locales/money.pt.yml +4 -0
- data/lib/money-rails/active_job/money_serializer.rb +19 -0
- data/lib/money-rails/active_record/monetizable.rb +17 -7
- data/lib/money-rails/configuration.rb +2 -2
- data/lib/money-rails/helpers/action_view_extension.rb +1 -1
- data/lib/money-rails/hooks.rb +11 -0
- data/lib/money-rails/version.rb +3 -1
- data/money-rails.gemspec +13 -26
- metadata +16 -225
- data/Rakefile +0 -84
- data/spec/active_record/migration_extensions/schema_statements_spec.rb +0 -101
- data/spec/active_record/migration_extensions/table_spec.rb +0 -104
- data/spec/active_record/monetizable_spec.rb +0 -1062
- data/spec/configuration_spec.rb +0 -147
- data/spec/dummy/README.rdoc +0 -261
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/assets/config/manifest.js +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +0 -15
- data/spec/dummy/app/assets/stylesheets/application.css +0 -13
- data/spec/dummy/app/controllers/application_controller.rb +0 -3
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
- data/spec/dummy/app/models/dummy_product.rb +0 -8
- data/spec/dummy/app/models/priceable.rb +0 -8
- data/spec/dummy/app/models/product.rb +0 -59
- data/spec/dummy/app/models/service.rb +0 -5
- data/spec/dummy/app/models/transaction.rb +0 -13
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config/application.rb +0 -66
- data/spec/dummy/config/boot.rb +0 -13
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -30
- data/spec/dummy/config/environments/production.rb +0 -69
- data/spec/dummy/config/environments/test.rb +0 -36
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/inflections.rb +0 -15
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/money.rb +0 -31
- data/spec/dummy/config/initializers/secret_token.rb +0 -7
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/en-GB.yml +0 -11
- data/spec/dummy/config/locales/en-US.yml +0 -5
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/locales/it.yml +0 -11
- data/spec/dummy/config/mongoid.yml +0 -29
- data/spec/dummy/config/routes.rb +0 -3
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/migrate/20120331190108_create_products.rb +0 -10
- data/spec/dummy/db/migrate/20120402080348_add_bonus_cents_to_product.rb +0 -6
- data/spec/dummy/db/migrate/20120524052716_create_services.rb +0 -10
- data/spec/dummy/db/migrate/20120528181002_create_transactions.rb +0 -11
- data/spec/dummy/db/migrate/20120528210103_create_dummy_products.rb +0 -10
- data/spec/dummy/db/migrate/20120607210247_add_column_that_allows_nil.rb +0 -5
- data/spec/dummy/db/migrate/20120712202655_add_sale_price_cents_to_product.rb +0 -7
- data/spec/dummy/db/migrate/20130124023419_add_price_in_a_range_cents_to_products.rb +0 -5
- data/spec/dummy/db/migrate/20140110194016_add_validates_method_amount_cents_to_products.rb +0 -5
- data/spec/dummy/db/migrate/20141005075025_add_aliased_attr_to_products.rb +0 -5
- data/spec/dummy/db/migrate/20150107061030_add_delivery_fee_cents_and_restock_fee_cents_to_product.rb +0 -6
- data/spec/dummy/db/migrate/20150126231442_add_reduced_price_to_products.rb +0 -6
- data/spec/dummy/db/migrate/20150213234410_add_special_price_to_products.rb +0 -5
- data/spec/dummy/db/migrate/20150217222612_add_lambda_price_to_products.rb +0 -5
- data/spec/dummy/db/migrate/20150303222230_add_skip_validation_price_cents_to_products.rb +0 -5
- data/spec/dummy/db/migrate/20151026220420_add_optional_amount_to_transactions.rb +0 -5
- data/spec/dummy/db/schema.rb +0 -59
- data/spec/dummy/db/structure.sql +0 -21
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -25
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -6
- data/spec/helpers/action_view_extension_spec.rb +0 -189
- data/spec/helpers/form_helper_spec.rb +0 -19
- data/spec/money_spec.rb +0 -40
- data/spec/mongoid/mongoid_spec.rb +0 -130
- data/spec/mongoid/two_spec.rb +0 -80
- data/spec/spec_helper.rb +0 -23
- data/spec/support/database_cleaner.rb +0 -14
- data/spec/test_helpers_spec.rb +0 -72
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f19bdc8ef198214c817707194397d89dcd4a4582839c3665fa44a5058eaf33bd
|
|
4
|
+
data.tar.gz: 04e6523eb3ed34e9ab2c2596c35fea84a415b38c7e0a57fbc9412f4aa71c0877
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6007152fd6ec545f080eb112e35a53e531bbaca69f635e630934c4f0662fa6f071fa62dabc42af779b6d1e68a5e419a4084f3da0006729768418e2a8f6637df8
|
|
7
|
+
data.tar.gz: 3450cf3305d2c5facc50e919ead251cacf95da4f414f35a924d96dee7c6970a23d197b411f18f4f839ac1e6583b2eee4c5409b7337ba443373c4b7c2808977c3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 2.0.0
|
|
6
|
+
|
|
7
|
+
- **Breaking change**: Requires `money` gem version ~> 7.0.
|
|
8
|
+
See the [Money 7.0 upgrading guide](https://github.com/RubyMoney/money/blob/main/UPGRADING-7.0.md)
|
|
9
|
+
- **Breaking change**: Requires `monetize` gem version ~> 7.0
|
|
10
|
+
- **Breaking change**: Drop support for Ruby < 3.1 and Rails < 6.1
|
|
11
|
+
- Allow monetizing methods with kwargs
|
|
12
|
+
- Fix `money_only_cents` for negative money
|
|
13
|
+
- Allow `nil` to be set as the default currency
|
|
14
|
+
- Portuguese translation for errors
|
|
15
|
+
- Skip subunit write for non-attributes in `read_monetized`
|
|
16
|
+
|
|
17
|
+
## 1.15.0
|
|
18
|
+
|
|
19
|
+
- Bump money version to ~> 6.16
|
|
20
|
+
- Tweak to invalid currency message
|
|
21
|
+
|
|
3
22
|
## 1.14.1
|
|
4
23
|
|
|
5
24
|
- Fix invalid_currency error definition
|
|
@@ -46,7 +65,7 @@
|
|
|
46
65
|
|
|
47
66
|
- Bump money version to ~> 6.12.0
|
|
48
67
|
- Bump monetize version to ~> 1.9.0
|
|
49
|
-
- BREAKING CHANGE: Fix to rounding logic in this version from 1.11.0 can cause breaking changes for those relying on the incorrect behavior.
|
|
68
|
+
- BREAKING CHANGE: Fix to rounding logic in this version from 1.11.0 can cause breaking changes for those relying on the incorrect behavior. See [the issue](https://github.com/RubyMoney/money-rails/issues/608) for details.
|
|
50
69
|
|
|
51
70
|
## 1.11.0
|
|
52
71
|
|
|
@@ -84,7 +103,7 @@
|
|
|
84
103
|
- Fix attribute order possibly affecting the value of monetized attribute
|
|
85
104
|
- Add support for RailsAdmin (use :money type)
|
|
86
105
|
- Raise error when gem was unable to infer monetized attribute name
|
|
87
|
-
- Revert decimal mark and thousands separator
|
|
106
|
+
- Revert decimal mark and thousands separator addition, since formatting should depend on country and locale, instead of currency
|
|
88
107
|
|
|
89
108
|
## 1.6.1
|
|
90
109
|
|
|
@@ -148,8 +167,8 @@
|
|
|
148
167
|
## 1.1.0
|
|
149
168
|
|
|
150
169
|
- Update dependencies to money 6.4.x and monetize 1.0.x.
|
|
151
|
-
- Make subunit setter (e.g. `#price_cents=`) set the `before_type_cast...`
|
|
152
|
-
|
|
170
|
+
- Make subunit setter (e.g. `#price_cents=`) set the `before_type_cast...`
|
|
171
|
+
variable. (Fixes validation errors.)
|
|
153
172
|
- use HashWithIndifferentAccess instead of Hash for
|
|
154
173
|
ActiveRecord::Base::monetized_attributes
|
|
155
174
|
- Let the 'monetize' test helper work when testing against the model's class,
|
|
@@ -159,7 +178,7 @@
|
|
|
159
178
|
- Upgrade specs to RSpec 3
|
|
160
179
|
- Use #respond_to? instead of #try? when monetizing an aliased attribute.
|
|
161
180
|
- Allow aliased attributes to be monetized
|
|
162
|
-
- Fix
|
|
181
|
+
- Fix compatibility issue with Rails 4.2
|
|
163
182
|
- Allow empty string as thousands separator.
|
|
164
183
|
- Allow using a lambda to set default_currency
|
|
165
184
|
|
|
@@ -292,4 +311,3 @@
|
|
|
292
311
|
## 0.0.1
|
|
293
312
|
|
|
294
313
|
- Hello World
|
|
295
|
-
|
data/LICENSE
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2012 Andreas Loupasakis
|
|
4
|
-
Copyright (c)
|
|
4
|
+
Copyright (c) 2025 Shane Emmons
|
|
5
5
|
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
# RubyMoney - Money-Rails
|
|
2
2
|
|
|
3
3
|
[](http://badge.fury.io/rb/money-rails)
|
|
4
|
-
[](https://codeclimate.com/github/RubyMoney/money-rails)
|
|
4
|
+
[](https://github.com/RubyMoney/money-rails/actions/workflows/ruby.yml)
|
|
6
5
|
[](http://opensource.org/licenses/MIT)
|
|
7
6
|
|
|
8
7
|
## Introduction
|
|
9
8
|
|
|
10
9
|
This library provides integration of the [money](http://github.com/Rubymoney/money) gem with Rails.
|
|
11
10
|
|
|
12
|
-
Use
|
|
11
|
+
Use `monetize` to specify which fields you want to be backed by
|
|
13
12
|
Money objects and helpers provided by the [money](http://github.com/Rubymoney/money)
|
|
14
13
|
gem.
|
|
15
14
|
|
|
@@ -20,26 +19,26 @@ welcome to contribute to the project.
|
|
|
20
19
|
|
|
21
20
|
## Installation
|
|
22
21
|
|
|
23
|
-
Add
|
|
22
|
+
Add it to your application’s Gemfile using:
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
$ bundle
|
|
24
|
+
```sh
|
|
25
|
+
bundle add money-rails
|
|
26
|
+
```
|
|
30
27
|
|
|
31
28
|
Or install it yourself using:
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
```sh
|
|
31
|
+
$ gem install money-rails
|
|
32
|
+
```
|
|
34
33
|
|
|
35
34
|
You can also use the money configuration initializer:
|
|
36
35
|
|
|
37
|
-
```
|
|
38
|
-
$ rails
|
|
36
|
+
```sh
|
|
37
|
+
$ bin/rails generate money_rails:initializer
|
|
39
38
|
```
|
|
40
39
|
|
|
41
40
|
There, you can define the default currency value and set other
|
|
42
|
-
configuration parameters for the
|
|
41
|
+
configuration parameters for the Rails app.
|
|
43
42
|
|
|
44
43
|
Without Rails in rack-based applications, call during initialization:
|
|
45
44
|
|
|
@@ -58,47 +57,44 @@ For example, we create a Product model which has an integer column called
|
|
|
58
57
|
|
|
59
58
|
```ruby
|
|
60
59
|
class Product < ActiveRecord::Base
|
|
61
|
-
|
|
62
60
|
monetize :price_cents
|
|
63
|
-
|
|
64
61
|
end
|
|
65
62
|
```
|
|
66
63
|
|
|
67
|
-
Now each Product object will also have an attribute called
|
|
64
|
+
Now each Product object will also have an attribute called `price` which
|
|
68
65
|
is a `Money` object, and can be used for money comparisons, conversions etc.
|
|
69
66
|
|
|
70
67
|
In this case the name of the money attribute is created automagically by removing the
|
|
71
|
-
|
|
68
|
+
`_cents` suffix from the column name.
|
|
72
69
|
|
|
73
|
-
If you are using another
|
|
74
|
-
money attribute, then you can provide an
|
|
75
|
-
|
|
70
|
+
If you are using another database column name, or you prefer another name for the
|
|
71
|
+
money attribute, then you can provide an `as` argument with a string value to the
|
|
72
|
+
`monetize` macro:
|
|
76
73
|
|
|
77
74
|
```ruby
|
|
78
75
|
monetize :discount_subunit, as: "discount"
|
|
79
76
|
```
|
|
80
77
|
|
|
81
|
-
Now the model objects will have a
|
|
82
|
-
object, wrapping the value of the
|
|
78
|
+
Now the model objects will have a `discount` attribute which is a `Money`
|
|
79
|
+
object, wrapping the value of the `discount_subunit` column with a Money
|
|
83
80
|
instance.
|
|
84
81
|
|
|
85
82
|
#### Migration helpers
|
|
86
83
|
|
|
87
|
-
If you want to add a money field to a product model you can use the
|
|
88
|
-
helper can be customized inside a
|
|
89
|
-
|
|
84
|
+
If you want to add a money field to a product model you can use the `add_monetize` helper.
|
|
85
|
+
This helper can be customized inside a `MoneyRails.configure` block. You should customize
|
|
86
|
+
the `add_monetize` helper to match the most common use case and utilize it across all
|
|
87
|
+
migrations.
|
|
90
88
|
|
|
91
89
|
```ruby
|
|
92
90
|
class MonetizeProduct < ActiveRecord::Migration
|
|
93
91
|
def change
|
|
94
|
-
|
|
95
|
-
add_monetize :products, :price # Rails 4x and above
|
|
92
|
+
add_monetize :products, :price
|
|
96
93
|
|
|
97
94
|
# OR
|
|
98
95
|
|
|
99
96
|
change_table :products do |t|
|
|
100
|
-
t.
|
|
101
|
-
t.monetize :price # Rails 4x and above
|
|
97
|
+
t.monetize :price
|
|
102
98
|
end
|
|
103
99
|
end
|
|
104
100
|
end
|
|
@@ -109,28 +105,23 @@ Another example, where the currency column is not included:
|
|
|
109
105
|
```ruby
|
|
110
106
|
class MonetizeItem < ActiveRecord::Migration
|
|
111
107
|
def change
|
|
112
|
-
|
|
108
|
+
add_monetize :items, :price, currency: { present: false }
|
|
113
109
|
end
|
|
114
110
|
end
|
|
115
111
|
```
|
|
116
112
|
|
|
117
|
-
Notice
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
migrations. If you're writing separate ```up``` and ```down``` methods, you
|
|
121
|
-
can use the ```remove_money``` helper.
|
|
122
|
-
|
|
123
|
-
##### Notice for Rails >= 4.2 and PG adapter
|
|
113
|
+
Notice: Default value of currency field, generated by migration’s helper, is
|
|
114
|
+
USD. To override these defaults, you need change the `default_currency` in an
|
|
115
|
+
initializer and run migrations.
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
`remove_monetize` to remove the column.
|
|
117
|
+
The `add_monetize` helper is reversible, so you can use it inside `change`
|
|
118
|
+
migrations. If you’re writing separate `up` and `down` methods, you can use the
|
|
119
|
+
`remove_monetize` helper.
|
|
129
120
|
|
|
130
121
|
#### Allow nil values
|
|
131
122
|
|
|
132
|
-
If you want to allow nil and/or blank values to a specific
|
|
133
|
-
|
|
123
|
+
If you want to allow `nil` and/or blank values to a specific monetized field,
|
|
124
|
+
you can use the `:allow_nil` parameter:
|
|
134
125
|
|
|
135
126
|
```ruby
|
|
136
127
|
# in Product model
|
|
@@ -138,7 +129,10 @@ monetize :optional_price_cents, allow_nil: true
|
|
|
138
129
|
|
|
139
130
|
# in Migration
|
|
140
131
|
def change
|
|
141
|
-
|
|
132
|
+
add_monetize :products,
|
|
133
|
+
:optional_price,
|
|
134
|
+
amount: { null: true, default: nil },
|
|
135
|
+
currency: { null: true, default: nil }
|
|
142
136
|
end
|
|
143
137
|
|
|
144
138
|
# now blank assignments are permitted
|
|
@@ -150,7 +144,8 @@ product.optional_price_cents # => nil
|
|
|
150
144
|
|
|
151
145
|
#### Allow large numbers
|
|
152
146
|
|
|
153
|
-
If you foresee that you will be saving large values (range is -2147483648 to
|
|
147
|
+
If you foresee that you will be saving large values (range is -2147483648 to
|
|
148
|
+
+2147483647 for Postgres), increase your integer column limit to `bigint`:
|
|
154
149
|
|
|
155
150
|
```ruby
|
|
156
151
|
def change
|
|
@@ -165,15 +160,17 @@ You can also pass along
|
|
|
165
160
|
such as this:
|
|
166
161
|
|
|
167
162
|
```ruby
|
|
168
|
-
monetize :price_in_a_range_cents,
|
|
163
|
+
monetize :price_in_a_range_cents,
|
|
164
|
+
allow_nil: true,
|
|
169
165
|
numericality: {
|
|
170
166
|
greater_than_or_equal_to: 0,
|
|
171
167
|
less_than_or_equal_to: 10000
|
|
172
168
|
}
|
|
173
169
|
```
|
|
174
170
|
|
|
175
|
-
Or, if you prefer, you can skip validations entirely for the attribute. This is
|
|
176
|
-
are aggregate methods and you wish to avoid executing
|
|
171
|
+
Or, if you prefer, you can skip validations entirely for the attribute. This is
|
|
172
|
+
useful if chosen attributes are aggregate methods and you wish to avoid executing
|
|
173
|
+
them on every record save.
|
|
177
174
|
|
|
178
175
|
```ruby
|
|
179
176
|
monetize :price_in_a_range_cents, disable_validation: true
|
|
@@ -186,6 +183,17 @@ to the validation you are willing to skip, like this:
|
|
|
186
183
|
monetize :price_in_a_range_cents, numericality: false
|
|
187
184
|
```
|
|
188
185
|
|
|
186
|
+
And you can also use `subunit_numericality` for subunit:
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
monetize :price_in_a_range_cents,
|
|
190
|
+
allow_nil: true,
|
|
191
|
+
subunit_numericality: {
|
|
192
|
+
greater_than_or_equal_to: 0,
|
|
193
|
+
less_than_or_equal_to: 100_00
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
189
197
|
### Mongoid 2.x and 3.x
|
|
190
198
|
|
|
191
199
|
`Money` is available as a field type to supply during a field definition:
|
|
@@ -231,18 +239,17 @@ Method return values can be monetized in the same way attributes are monetized.
|
|
|
231
239
|
|
|
232
240
|
```ruby
|
|
233
241
|
class Transaction < ActiveRecord::Base
|
|
234
|
-
|
|
235
242
|
monetize :price_cents
|
|
236
243
|
monetize :tax_cents
|
|
237
244
|
monetize :total_cents
|
|
245
|
+
|
|
238
246
|
def total_cents
|
|
239
|
-
|
|
247
|
+
price_cents + tax_cents
|
|
240
248
|
end
|
|
241
|
-
|
|
242
249
|
end
|
|
243
250
|
```
|
|
244
251
|
|
|
245
|
-
Now each Transaction object has a method called `total` which returns a `Money` object.
|
|
252
|
+
Now each `Transaction` object has a method called `total` which returns a `Money` object.
|
|
246
253
|
|
|
247
254
|
### Currencies
|
|
248
255
|
|
|
@@ -254,14 +261,12 @@ initializer of money-rails:
|
|
|
254
261
|
```ruby
|
|
255
262
|
# config/initializers/money.rb
|
|
256
263
|
MoneyRails.configure do |config|
|
|
257
|
-
|
|
258
264
|
# set the default currency
|
|
259
265
|
config.default_currency = :usd
|
|
260
|
-
|
|
261
266
|
end
|
|
262
267
|
```
|
|
263
|
-
For complete list of available currency: [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217)
|
|
264
268
|
|
|
269
|
+
For a complete list of available currencies: [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217)
|
|
265
270
|
|
|
266
271
|
If you need to set the default currency on a per-request basis, such as in a
|
|
267
272
|
multi-tenant application, you may use a lambda to lazy-load the default currency
|
|
@@ -270,65 +275,73 @@ from a field in a configuration model called `Tenant` in this example:
|
|
|
270
275
|
```ruby
|
|
271
276
|
# config/initializers/money.rb
|
|
272
277
|
MoneyRails.configure do |config|
|
|
273
|
-
|
|
274
278
|
# set the default currency based on client configuration
|
|
275
279
|
config.default_currency = -> { Tenant.current.default_currency }
|
|
276
280
|
end
|
|
277
281
|
```
|
|
278
282
|
|
|
283
|
+
Be aware that this **does not work in Rails 7+**, as the lambda is evaluated
|
|
284
|
+
immediately, and therefore requires your model to be already loaded.
|
|
285
|
+
Workarounds include wrapping the initialization in
|
|
286
|
+
`ActiveSupport::Reloader.to_prepare`, or creating a function that rescues
|
|
287
|
+
unloaded constants with an initialization-time default, and running that in your lambda.
|
|
288
|
+
|
|
279
289
|
In many cases this is not enough, so there are some other options to
|
|
280
290
|
meet your needs.
|
|
281
291
|
|
|
282
292
|
#### Model Currency
|
|
283
293
|
|
|
284
294
|
You can override the global default currency within a specific ActiveRecord
|
|
285
|
-
model using the
|
|
295
|
+
model using the `register_currency` macro:
|
|
286
296
|
|
|
287
297
|
```ruby
|
|
288
298
|
# app/models/product.rb
|
|
289
299
|
class Product < ActiveRecord::Base
|
|
290
|
-
|
|
291
300
|
# Use EUR as model level currency
|
|
292
301
|
register_currency :eur
|
|
293
302
|
|
|
294
303
|
monetize :discount_subunit, as: "discount"
|
|
295
304
|
monetize :bonus_cents
|
|
296
|
-
|
|
297
305
|
end
|
|
298
306
|
```
|
|
299
307
|
|
|
300
|
-
Now
|
|
301
|
-
|
|
308
|
+
Now `product.discount` and `product.bonus` will return a `Money` object using
|
|
309
|
+
EUR as their currency, instead of the default USD.
|
|
302
310
|
|
|
303
311
|
(This is not available in Mongoid).
|
|
304
312
|
|
|
305
|
-
#### Attribute Currency (
|
|
313
|
+
#### Attribute Currency (`:with_currency`)
|
|
306
314
|
|
|
307
|
-
By passing the option
|
|
308
|
-
with a currency code (symbol or string) or a callable object (object that responds
|
|
309
|
-
|
|
310
|
-
|
|
315
|
+
By passing the option `:with_currency` to the `monetize` macro call,
|
|
316
|
+
with a currency code (symbol or string) or a callable object (object that responds
|
|
317
|
+
to the `call` method) that returns a currency code, as its value, you can define
|
|
318
|
+
a currency in a more granular way. This will let you attach the given currency
|
|
319
|
+
only to the specified monetized model attribute (allowing you to, for example,
|
|
320
|
+
monetize different attributes of the same model with different currencies).
|
|
311
321
|
|
|
312
|
-
This allows you to override both the model level and the global
|
|
313
|
-
|
|
322
|
+
This allows you to override both the model level and the global default
|
|
323
|
+
currencies:
|
|
314
324
|
|
|
315
325
|
```ruby
|
|
316
326
|
# app/models/product.rb
|
|
317
327
|
class Product < ActiveRecord::Base
|
|
318
|
-
|
|
319
328
|
# Use EUR as the model level currency
|
|
320
329
|
register_currency :eur
|
|
321
330
|
|
|
322
331
|
monetize :discount_subunit, as: "discount"
|
|
323
332
|
monetize :bonus_cents, with_currency: :gbp
|
|
324
|
-
|
|
325
333
|
end
|
|
326
334
|
```
|
|
327
335
|
|
|
328
|
-
In this case
|
|
329
|
-
currency, whereas
|
|
336
|
+
In this case `product.bonus` will return a Money object with GBP as its
|
|
337
|
+
currency, whereas `product.discount.currency.to_s # => EUR`
|
|
330
338
|
|
|
331
|
-
As mentioned earlier you can use an object that responds to the method
|
|
339
|
+
As mentioned earlier you can use an object that responds to the method `call`
|
|
340
|
+
and accepts the model instance as a parameter. That means you can use a `Proc`
|
|
341
|
+
or `lambda` (we would recommend `lambda` over `Proc` because of their
|
|
342
|
+
[different control flow characteristics](https://stackoverflow.com/questions/1740046/whats-the-difference-between-a-proc-and-a-lambda-in-ruby))
|
|
343
|
+
or even define a separate `class` with an instance or class method (maybe even a
|
|
344
|
+
`module`) to return the currency code:
|
|
332
345
|
|
|
333
346
|
```ruby
|
|
334
347
|
class DeliveryFee
|
|
@@ -343,9 +356,7 @@ module OptionalPrice
|
|
|
343
356
|
end
|
|
344
357
|
end
|
|
345
358
|
|
|
346
|
-
# app/models/product.rb
|
|
347
359
|
class Product < ActiveRecord::Base
|
|
348
|
-
|
|
349
360
|
monetize :price_cents, with_currency: ->(_product) { :gbp }
|
|
350
361
|
monetize :delivery_fee_cents, with_currency: DeliveryFee.new
|
|
351
362
|
monetize :optional_price_cents, with_currency: OptionalPrice
|
|
@@ -356,9 +367,9 @@ end
|
|
|
356
367
|
|
|
357
368
|
All the previous options do not require any extra model fields to hold
|
|
358
369
|
the currency values. If the currency of a field will vary from
|
|
359
|
-
one model instance to another, then you should add a column called
|
|
360
|
-
to your database table and pass the option
|
|
361
|
-
to the
|
|
370
|
+
one model instance to another, then you should add a column called `currency`
|
|
371
|
+
to your database table and pass the option `with_model_currency`
|
|
372
|
+
to the `monetize` macro.
|
|
362
373
|
|
|
363
374
|
money-rails will use this knowledge to override the model level and global
|
|
364
375
|
default values. Non-nil instance currency values also override attribute
|
|
@@ -366,7 +377,6 @@ currency values, so they have the highest precedence.
|
|
|
366
377
|
|
|
367
378
|
```ruby
|
|
368
379
|
class Transaction < ActiveRecord::Base
|
|
369
|
-
|
|
370
380
|
# This model has a separate currency column
|
|
371
381
|
attr_accessible :amount_cents, :currency, :tax_cents
|
|
372
382
|
|
|
@@ -375,7 +385,6 @@ class Transaction < ActiveRecord::Base
|
|
|
375
385
|
|
|
376
386
|
monetize :amount_cents, with_model_currency: :currency
|
|
377
387
|
monetize :tax_cents, with_model_currency: :currency
|
|
378
|
-
|
|
379
388
|
end
|
|
380
389
|
|
|
381
390
|
# Now instantiating with a specific currency overrides
|
|
@@ -386,11 +395,10 @@ t.amount == Money.new(2500, "CAD") # true
|
|
|
386
395
|
|
|
387
396
|
### Configuration parameters
|
|
388
397
|
|
|
389
|
-
You can handle a bunch of configuration params through
|
|
398
|
+
You can handle a bunch of configuration params through `money.rb` initializer:
|
|
390
399
|
|
|
391
400
|
```ruby
|
|
392
401
|
MoneyRails.configure do |config|
|
|
393
|
-
|
|
394
402
|
# To set the default currency
|
|
395
403
|
#
|
|
396
404
|
# config.default_currency = :usd
|
|
@@ -471,25 +479,32 @@ MoneyRails.configure do |config|
|
|
|
471
479
|
# symbol: nil,
|
|
472
480
|
# sign_before_symbol: nil
|
|
473
481
|
# }
|
|
482
|
+
|
|
483
|
+
# Set whether an error should be raised when parsing money values
|
|
484
|
+
# This includes assigning to a monetized field with the wrong currency
|
|
485
|
+
# Default value is false
|
|
486
|
+
#
|
|
487
|
+
# config.raise_error_on_money_parsing = true
|
|
474
488
|
end
|
|
475
489
|
```
|
|
476
490
|
|
|
477
|
-
*
|
|
478
|
-
*
|
|
491
|
+
* `default_currency`: Set the default (application wide) currency (USD is the default)
|
|
492
|
+
* `include_validations`: Permit the inclusion of a `validates_numericality_of`
|
|
479
493
|
validation for each monetized field (the default is true)
|
|
480
|
-
*
|
|
494
|
+
* `register_currency`: Register one custom currency. This option can be
|
|
481
495
|
used more than once to set more custom currencies. The value should be
|
|
482
|
-
a hash of all the necessary key/value pairs (important keys:
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
*
|
|
486
|
-
|
|
487
|
-
*
|
|
496
|
+
a hash of all the necessary key/value pairs (important keys: `:priority`, `:iso_code`,
|
|
497
|
+
`:name`, `:symbol`, `:symbol_first`, `:subunit`, `:subunit_to_unit`,
|
|
498
|
+
`:thousands_separator`, `:decimal_mark`).
|
|
499
|
+
* `add_rate`: Provide custom exchange rate for currencies in one direction only! This
|
|
500
|
+
rate is added to the attached bank object.
|
|
501
|
+
* `default_bank`: The default bank object holding exchange rates etc.
|
|
488
502
|
(https://github.com/RubyMoney/money#currency-exchange)
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
503
|
+
* `default_format`: Force `Money#format` to use these options for formatting.
|
|
504
|
+
* `amount_column`: Provide values for the amount column (holding the fractional part of a money object).
|
|
505
|
+
* `currency_column`: Provide default values or even disable (`present: false`) the currency column.
|
|
506
|
+
* `rounding_mode`: Set `Money.rounding_mode` to one of the BigDecimal constants.
|
|
507
|
+
* `raise_error_on_money_parsing`: Set whether errors should be raised when parsing money values
|
|
493
508
|
|
|
494
509
|
### Helpers
|
|
495
510
|
|
|
@@ -504,7 +519,7 @@ _For examples below, `@money_object == <Money fractional:650 currency:USD>`_
|
|
|
504
519
|
| `money_without_cents_and_with_symbol @money_object` | $6 |
|
|
505
520
|
| `money_only_cents @money_object` | 50 |
|
|
506
521
|
|
|
507
|
-
#### `no_cents_if_whole`
|
|
522
|
+
#### `no_cents_if_whole` configuration param
|
|
508
523
|
|
|
509
524
|
`humanized_money` and `humanized_money_with_symbol` will not render the cents part if it contains only zeros, unless `config.no_cents_if_whole` is set to `false` in the `money.rb` configuration (default: true).
|
|
510
525
|
Note that the `config.default_format` will be overwritten by `config.no_cents_if_whole`.
|
|
@@ -513,23 +528,26 @@ So `humanized_money` will ignore `config.default_format = { no_cents_if_whole: f
|
|
|
513
528
|
### Testing
|
|
514
529
|
|
|
515
530
|
If you use Rspec there is a test helper implementation.
|
|
516
|
-
Just write `require "money-rails/test_helpers"` in spec_helper.rb
|
|
531
|
+
Just write `require "money-rails/test_helpers"` in `spec_helper.rb`.
|
|
517
532
|
|
|
518
|
-
|
|
533
|
+
#### The `monetize` matcher
|
|
519
534
|
|
|
520
535
|
```ruby
|
|
521
536
|
is_expected.to monetize(:price)
|
|
522
537
|
```
|
|
538
|
+
|
|
523
539
|
This will ensure that a column called `price_cents` is being monetized.
|
|
524
540
|
|
|
525
541
|
```ruby
|
|
526
542
|
is_expected.to monetize(:price).allow_nil
|
|
527
543
|
```
|
|
544
|
+
|
|
528
545
|
By using `allow_nil` you can specify money attributes that accept nil values.
|
|
529
546
|
|
|
530
547
|
```ruby
|
|
531
548
|
is_expected.to monetize(:price).as(:discount_value)
|
|
532
549
|
```
|
|
550
|
+
|
|
533
551
|
By using `as` chain you can specify the exact name to which a monetized
|
|
534
552
|
column is being mapped.
|
|
535
553
|
|
|
@@ -552,14 +570,15 @@ For examples on using the test_helpers look at
|
|
|
552
570
|
|
|
553
571
|
## Supported ORMs/ODMs
|
|
554
572
|
|
|
555
|
-
* ActiveRecord (>=
|
|
573
|
+
* ActiveRecord (>= 6.1)
|
|
556
574
|
* Mongoid (>= 2.x)
|
|
557
575
|
|
|
558
576
|
## Supported Ruby interpreters
|
|
559
577
|
|
|
560
|
-
* MRI Ruby >=
|
|
578
|
+
* MRI Ruby >= 3.0
|
|
561
579
|
|
|
562
|
-
You can see a full list of the currently supported interpreters in
|
|
580
|
+
You can see a full list of the currently supported interpreters in
|
|
581
|
+
[ruby.yml](https://github.com/RubyMoney/money-rails/blob/main/.github/workflows/ruby.yml)
|
|
563
582
|
|
|
564
583
|
## Contributing
|
|
565
584
|
|
|
@@ -587,4 +606,4 @@ If you are testing against mongoid, make sure to have the mongod process running
|
|
|
587
606
|
|
|
588
607
|
## License
|
|
589
608
|
|
|
590
|
-
MIT License. Copyright
|
|
609
|
+
[MIT License](https://github.com/RubyMoney/money-rails/blob/main/LICENSE). Copyright 2023 RubyMoney.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MoneyRails
|
|
4
|
+
module ActiveJob
|
|
5
|
+
class MoneySerializer < ::ActiveJob::Serializers::ObjectSerializer
|
|
6
|
+
def serialize?(argument)
|
|
7
|
+
argument.is_a?(Money)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def serialize(money)
|
|
11
|
+
super("cents" => money.cents, "currency" => money.currency.to_s)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def deserialize(hash)
|
|
15
|
+
Money.new(hash["cents"], hash["currency"])
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -10,7 +10,7 @@ module MoneyRails
|
|
|
10
10
|
|
|
11
11
|
module ClassMethods
|
|
12
12
|
def monetized_attributes
|
|
13
|
-
monetized_attributes = @monetized_attributes || {}
|
|
13
|
+
monetized_attributes = @monetized_attributes || {}.with_indifferent_access
|
|
14
14
|
|
|
15
15
|
if superclass.respond_to?(:monetized_attributes)
|
|
16
16
|
monetized_attributes.merge(superclass.monetized_attributes)
|
|
@@ -118,8 +118,8 @@ module MoneyRails
|
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
# Getter for monetized attribute
|
|
121
|
-
define_method name do |*args|
|
|
122
|
-
read_monetized name, subunit_name, options, *args
|
|
121
|
+
define_method name do |*args, **kwargs|
|
|
122
|
+
read_monetized name, subunit_name, options, *args, **kwargs
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
# Setter for monetized attribute
|
|
@@ -178,9 +178,19 @@ module MoneyRails
|
|
|
178
178
|
end
|
|
179
179
|
end
|
|
180
180
|
|
|
181
|
-
def read_monetized(name, subunit_name, options =
|
|
182
|
-
#
|
|
183
|
-
|
|
181
|
+
def read_monetized(name, subunit_name, options = nil, *args, **kwargs)
|
|
182
|
+
# Ruby 2.x compatibility
|
|
183
|
+
if options.nil?
|
|
184
|
+
options = kwargs
|
|
185
|
+
kwargs = {}
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
if kwargs.any?
|
|
189
|
+
amount = public_send(subunit_name, *args, **kwargs)
|
|
190
|
+
else
|
|
191
|
+
# Ruby 2.x does not allow empty kwargs
|
|
192
|
+
amount = public_send(subunit_name, *args)
|
|
193
|
+
end
|
|
184
194
|
|
|
185
195
|
return if amount.nil? && options[:allow_nil]
|
|
186
196
|
# Get the currency object
|
|
@@ -195,7 +205,7 @@ module MoneyRails
|
|
|
195
205
|
result = memoized
|
|
196
206
|
else
|
|
197
207
|
memoized_amount = memoized.amount.to_money(attr_currency)
|
|
198
|
-
write_attribute subunit_name, memoized_amount.cents
|
|
208
|
+
write_attribute subunit_name, memoized_amount.cents if has_attribute? subunit_name
|
|
199
209
|
# Cache the value (it may be nil)
|
|
200
210
|
result = instance_variable_set("@#{name}", memoized_amount)
|
|
201
211
|
end
|