money-rails 0.7.1 → 0.8.1
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.
- data/CHANGELOG.md +13 -0
- data/README.md +111 -25
- data/Rakefile +3 -3
- data/lib/generators/templates/money.rb +8 -2
- data/lib/money-rails.rb +1 -0
- data/lib/money-rails/active_model/validator.rb +12 -9
- data/lib/money-rails/active_record/monetizable.rb +13 -6
- data/lib/money-rails/configuration.rb +23 -0
- data/lib/money-rails/helpers/action_view_extension.rb +27 -12
- data/lib/money-rails/hooks.rb +2 -4
- data/lib/money-rails/money.rb +23 -0
- data/lib/money-rails/mongoid/{three.rb → money.rb} +1 -1
- data/lib/money-rails/test_helpers.rb +49 -0
- data/lib/money-rails/version.rb +1 -1
- data/money-rails.gemspec +9 -3
- data/spec/active_record/migration_extensions/schema_statements_spec.rb +3 -1
- data/spec/active_record/migration_extensions/table_spec.rb +3 -1
- data/spec/active_record/monetizable_spec.rb +46 -4
- data/spec/configuration_spec.rb +63 -0
- data/spec/dummy/app/models/product.rb +7 -0
- data/spec/dummy/db/migrate/20130124023419_add_price_in_a_range_cents_to_products.rb +5 -0
- data/spec/dummy/db/schema.rb +5 -1
- data/spec/dummy/db/structure.sql +4 -2
- data/spec/helpers/action_view_extension_spec.rb +25 -2
- data/spec/mongoid/three_spec.rb +14 -0
- data/spec/test_helpers_spec.rb +31 -0
- metadata +99 -101
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -1
- data/spec/dummy/log/test.log +0 -17903
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## master
|
4
|
+
|
5
|
+
## 0.8.0
|
6
|
+
- Added defaults for amount and currency columns in database schema, based on the default currency.
|
7
|
+
- Use a better default subunit_unit name (choose the value of column.postfix set in the config).
|
8
|
+
- Began support of Rails 4.
|
9
|
+
- Added global settings for money object formatted output (:no_cents_if_whole, :symbol options).
|
10
|
+
- Enhanced money validator.
|
11
|
+
- Added ability to use numericality validations on monetize (GH-70).
|
12
|
+
- Fixed error caused by ActiveSupport::HashWithIndifferentAccess
|
13
|
+
(GH-62).
|
14
|
+
- Added money-rails test helper (rspec matcher).
|
15
|
+
|
3
16
|
## 0.7.1
|
4
17
|
- Fix error when instantiating new model in mongoid extension (GH-60)
|
5
18
|
|
data/README.md
CHANGED
@@ -44,29 +44,6 @@ configuration parameters for the rails app.
|
|
44
44
|
|
45
45
|
### ActiveRecord
|
46
46
|
|
47
|
-
#### Migration helpers
|
48
|
-
|
49
|
-
If you want to add money field to product model you may use ```add_money``` helper. That
|
50
|
-
helper might be customized inside ```MoneyRails.configure``` block. You should customize
|
51
|
-
```add_money``` helper to match the most common use case and utilize it across all migrations.
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
class MonetizeProduct < ActiveRecord::Migration
|
55
|
-
def change
|
56
|
-
add_money :products, :price
|
57
|
-
|
58
|
-
# OR
|
59
|
-
|
60
|
-
change_table :products do |t|
|
61
|
-
t.money :price
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
```
|
66
|
-
|
67
|
-
```add_money``` helper is revertable, so you may use it inside ```change``` migrations.
|
68
|
-
If you writing separate ```up``` and ```down``` methods, you may use ```remove_money``` helper.
|
69
|
-
|
70
47
|
#### Usage example
|
71
48
|
|
72
49
|
For example, we create a Product model which has an integer price_cents column
|
@@ -98,6 +75,39 @@ Now the model objects will have a ```discount``` attribute which
|
|
98
75
|
is a Money object, wrapping the value of ```discount_subunit``` column to a
|
99
76
|
Money instance.
|
100
77
|
|
78
|
+
#### Migration helpers
|
79
|
+
|
80
|
+
If you want to add money field to product model you may use ```add_money``` helper. That
|
81
|
+
helper might be customized inside ```MoneyRails.configure``` block. You should customize
|
82
|
+
```add_money``` helper to match the most common use case and utilize it across all migrations.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class MonetizeProduct < ActiveRecord::Migration
|
86
|
+
def change
|
87
|
+
add_money :products, :price
|
88
|
+
|
89
|
+
# OR
|
90
|
+
|
91
|
+
change_table :products do |t|
|
92
|
+
t.money :price
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
Another example where the currency column is not including:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
class MonetizeItem < ActiveRecord::Migration
|
102
|
+
def change
|
103
|
+
add_money :items, :price, currency: { present: false }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
```add_money``` helper is revertable, so you may use it inside ```change``` migrations.
|
109
|
+
If you writing separate ```up``` and ```down``` methods, you may use ```remove_money``` helper.
|
110
|
+
|
101
111
|
#### Allow nil values
|
102
112
|
|
103
113
|
If you want to allow the assignment of nil and/or blank values to a specific
|
@@ -114,6 +124,20 @@ product.optional_price # => nil
|
|
114
124
|
product.optional_price_cents # => nil
|
115
125
|
```
|
116
126
|
|
127
|
+
#### Numericality validation options
|
128
|
+
|
129
|
+
You can also pass along
|
130
|
+
[numericality validation options](http://guides.rubyonrails.org/active_record_validations_callbacks.html#numericality)
|
131
|
+
such as this:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
monetize :price_in_a_range_cents, :allow_nil => true,
|
135
|
+
:numericality => {
|
136
|
+
:greater_than_or_equal_to => 0,
|
137
|
+
:less_than_or_equal_to => 10000
|
138
|
+
}
|
139
|
+
```
|
140
|
+
|
117
141
|
### Mongoid 2.x and 3.x
|
118
142
|
|
119
143
|
`Money` is available as a field type to supply during a field definition:
|
@@ -290,6 +314,26 @@ MoneyRails.configure do |config|
|
|
290
314
|
#
|
291
315
|
config.include_validations = true
|
292
316
|
|
317
|
+
# Default ActiveRecord migration configuration values for columns:
|
318
|
+
#
|
319
|
+
# config.amount_column = { prefix: '', # column name prefix
|
320
|
+
# postfix: '_cents', # column name postfix
|
321
|
+
# column_name: nil, # full column name (overrides prefix, postfix and accessor name)
|
322
|
+
# type: :integer, # column type
|
323
|
+
# present: true, # column will be created
|
324
|
+
# null: false, # other options will be treated as column options
|
325
|
+
# default: 0
|
326
|
+
# }
|
327
|
+
#
|
328
|
+
# config.currency_column = { prefix: '',
|
329
|
+
# postfix: '_currency',
|
330
|
+
# column_name: nil,
|
331
|
+
# type: :string,
|
332
|
+
# present: true,
|
333
|
+
# null: false,
|
334
|
+
# default: 'USD'
|
335
|
+
# }
|
336
|
+
|
293
337
|
# Register a custom currency
|
294
338
|
#
|
295
339
|
# config.register_currency = {
|
@@ -303,10 +347,17 @@ MoneyRails.configure do |config|
|
|
303
347
|
# :thousands_separator => ".",
|
304
348
|
# :decimal_mark => ","
|
305
349
|
# }
|
350
|
+
|
351
|
+
# Set money formatted output globally.
|
352
|
+
# Default value is nil meaning "ignore this option".
|
353
|
+
# Options are nil, true, false.
|
354
|
+
#
|
355
|
+
# config.no_cents_if_whole = nil
|
356
|
+
# config.symbol = nil
|
306
357
|
end
|
307
358
|
```
|
308
359
|
|
309
|
-
* ```
|
360
|
+
* ```default_currency```: Set the default (application wide) currency (USD is the default)
|
310
361
|
* ```include_validations```: Permit the inclusion of a ```validates_numericality_of```
|
311
362
|
validation for each monetized field (the default is true)
|
312
363
|
* ```register_currency```: Register one custom currency. This option can be
|
@@ -318,6 +369,11 @@ end
|
|
318
369
|
only! This rate is added to the attached bank object.
|
319
370
|
* ```default_bank```: The default bank object holding exchange rates etc.
|
320
371
|
(https://github.com/RubyMoney/money#currency-exchange)
|
372
|
+
* ```no_cents_if_whole```: Force `Money#format` method to use its value as the default for ```no_cents_if_whole``` key.
|
373
|
+
* ```symbol```: Use its value as the default for ```symbol``` key in
|
374
|
+
`Money#format` method.
|
375
|
+
* ```amount_column```: Provide values for the amount column (holding the fractional part of a money object).
|
376
|
+
* ```currency_column```: Provide default values or even disable (`present: false`) the currency column.
|
321
377
|
|
322
378
|
### Helpers
|
323
379
|
|
@@ -335,7 +391,7 @@ This will render a `span` dom element with the default currency symbol.
|
|
335
391
|
```
|
336
392
|
This will render a formatted money value without the currency symbol and
|
337
393
|
without the cents part if it contains only zeros (uses
|
338
|
-
`:
|
394
|
+
`:no_cents_if_whole flag`).
|
339
395
|
|
340
396
|
* humanize with symbol helper
|
341
397
|
|
@@ -362,6 +418,36 @@ without the cents part.
|
|
362
418
|
This will render a formatted money value including the currency symbol and
|
363
419
|
without the cents part.
|
364
420
|
|
421
|
+
### Testing
|
422
|
+
|
423
|
+
If you use Rspec there is an test helper implementation.
|
424
|
+
Just write `require "money-rails/test_helpers"` in spec_helper.rb and
|
425
|
+
`include MoneyRails::TestHelpers` inside a describe block you want to
|
426
|
+
use the helper.
|
427
|
+
|
428
|
+
* the `monetize` matcher
|
429
|
+
|
430
|
+
```
|
431
|
+
monetize(:price_cents).should be_true
|
432
|
+
```
|
433
|
+
This will ensure that a column called `price_cents` is being monetized.
|
434
|
+
|
435
|
+
```
|
436
|
+
monetize(:price_cents).as(:discount_value).should be_true
|
437
|
+
```
|
438
|
+
By using `as` chain you can specify the exact name to which a monetized
|
439
|
+
column is being mapped.
|
440
|
+
|
441
|
+
```
|
442
|
+
monetize(:price_cents).with_currency(:gbp).should be_true
|
443
|
+
```
|
444
|
+
|
445
|
+
By using the `with_currency` chain you can specify the expected currency
|
446
|
+
for the chosen money attribute. (You can also combine all the chains.)
|
447
|
+
|
448
|
+
For examples on using the test_helpers look at
|
449
|
+
[test_helpers_spec.rb](https://github.com/RubyMoney/money-rails/blob/master/spec/test_helpers_spec.rb)
|
450
|
+
|
365
451
|
## Supported ORMs/ODMs
|
366
452
|
|
367
453
|
* ActiveRecord (>= 3.x)
|
data/Rakefile
CHANGED
@@ -54,7 +54,7 @@ namespace :spec do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
desc "Update
|
58
|
-
task :
|
59
|
-
sh "git shortlog -s | awk '{ print $2 \" \" $3 }' >
|
57
|
+
desc "Update CONTRIBUTORS file"
|
58
|
+
task :contributors do
|
59
|
+
sh "git shortlog -s | awk '{ print $2 \" \" $3 }' > CONTRIBUTORS"
|
60
60
|
end
|
@@ -4,7 +4,7 @@ MoneyRails.configure do |config|
|
|
4
4
|
|
5
5
|
# To set the default currency
|
6
6
|
#
|
7
|
-
#config.default_currency = :usd
|
7
|
+
# config.default_currency = :usd
|
8
8
|
|
9
9
|
# Set default bank object
|
10
10
|
#
|
@@ -21,7 +21,7 @@ MoneyRails.configure do |config|
|
|
21
21
|
# To handle the inclusion of validations for monetized fields
|
22
22
|
# The default value is true
|
23
23
|
#
|
24
|
-
#config.include_validations = true
|
24
|
+
# config.include_validations = true
|
25
25
|
|
26
26
|
# Default ActiveRecord migration configuration values for columns:
|
27
27
|
#
|
@@ -58,4 +58,10 @@ MoneyRails.configure do |config|
|
|
58
58
|
# :decimal_mark => ","
|
59
59
|
# }
|
60
60
|
|
61
|
+
# Set money formatted output globally.
|
62
|
+
# Default value is nil meaning "ignore this option".
|
63
|
+
# Options are nil, true, false.
|
64
|
+
#
|
65
|
+
# config.no_cents_if_whole = nil
|
66
|
+
# config.symbol = nil
|
61
67
|
end
|
data/lib/money-rails.rb
CHANGED
@@ -23,15 +23,17 @@ module MoneyRails
|
|
23
23
|
thousands_separator = I18n.t('number.currency.format.delimiter', default: currency.thousands_separator)
|
24
24
|
symbol = I18n.t('number.currency.format.unit', default: currency.symbol)
|
25
25
|
|
26
|
-
raw_value = raw_value.to_s.gsub(symbol, "")
|
26
|
+
raw_value = raw_value.to_s.gsub(symbol, "")
|
27
|
+
abs_raw_value = raw_value.gsub(/^-/, "")
|
27
28
|
|
28
|
-
decimal_pieces =
|
29
|
+
decimal_pieces = abs_raw_value.split(decimal_mark)
|
29
30
|
|
30
|
-
# check for numbers like 12.23.45
|
31
|
-
|
31
|
+
# check for numbers like '12.23.45' or '....'
|
32
|
+
unless [1, 2].include? decimal_pieces.length
|
32
33
|
record.errors.add(attr, I18n.t('errors.messages.invalid_currency',
|
33
34
|
{ :thousands => thousands_separator,
|
34
35
|
:decimal => decimal_mark }))
|
36
|
+
return
|
35
37
|
end
|
36
38
|
|
37
39
|
pieces = decimal_pieces[0].split(thousands_separator)
|
@@ -48,11 +50,12 @@ module MoneyRails
|
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
# Remove thousands separators, normalize decimal mark,
|
54
|
+
# remove whitespaces and _ (E.g. 99 999 999 or 12_300_200.20)
|
55
|
+
raw_value = raw_value.to_s
|
56
|
+
.gsub(thousands_separator, '')
|
57
|
+
.gsub(decimal_mark, '.')
|
58
|
+
.gsub(/[\s_]/, '')
|
56
59
|
end
|
57
60
|
super(record, attr, raw_value)
|
58
61
|
end
|
@@ -35,12 +35,12 @@ module MoneyRails
|
|
35
35
|
|
36
36
|
# Form target name for the money backed ActiveModel field:
|
37
37
|
# if a target name is provided then use it
|
38
|
-
# if there is a "
|
38
|
+
# if there is a "_{column.postfix}" suffix then just remove it to create the target name
|
39
39
|
# if none of the previous is the case then use a default suffix
|
40
40
|
if name
|
41
41
|
name = name.to_s
|
42
|
-
elsif subunit_name =~
|
43
|
-
name = subunit_name.sub(
|
42
|
+
elsif subunit_name =~ /#{MoneyRails::Configuration.amount_column[:postfix]}$/
|
43
|
+
name = subunit_name.sub(/#{MoneyRails::Configuration.amount_column[:postfix]}$/, "")
|
44
44
|
else
|
45
45
|
# FIXME: provide a better default
|
46
46
|
name = [subunit_name, "money"].join("_")
|
@@ -57,10 +57,17 @@ module MoneyRails
|
|
57
57
|
|
58
58
|
# Include numericality validation if needed
|
59
59
|
if MoneyRails.include_validations
|
60
|
-
|
61
|
-
|
60
|
+
validation_options = {
|
61
|
+
:allow_nil => options[:allow_nil],
|
62
|
+
:numericality => true
|
63
|
+
}
|
64
|
+
validates subunit_name, validation_options
|
65
|
+
|
66
|
+
validation_options = { :allow_nil => options[:allow_nil] }
|
67
|
+
validation_options = options[:numericality].merge(validation_options) if options[:numericality]
|
68
|
+
|
62
69
|
# Allow only Money objects or Numeric values!
|
63
|
-
validates name.to_sym, 'money_rails/active_model/money' =>
|
70
|
+
validates name.to_sym, 'money_rails/active_model/money' => validation_options
|
64
71
|
end
|
65
72
|
|
66
73
|
define_method name do |*args|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/module/delegation'
|
2
2
|
require 'active_support/core_ext/module/attribute_accessors'
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
3
4
|
|
4
5
|
module MoneyRails
|
5
6
|
|
@@ -19,9 +20,15 @@ module MoneyRails
|
|
19
20
|
|
20
21
|
# Configuration parameters
|
21
22
|
|
23
|
+
def default_currency
|
24
|
+
Money.default_currency
|
25
|
+
end
|
26
|
+
|
22
27
|
# Set default currency of money library
|
23
28
|
def default_currency=(currency_name)
|
24
29
|
Money.default_currency = Money::Currency.new(currency_name)
|
30
|
+
set_amount_column_for_default_currency!
|
31
|
+
set_currency_column_for_default_currency!
|
25
32
|
end
|
26
33
|
|
27
34
|
# Register a custom currency
|
@@ -29,6 +36,15 @@ module MoneyRails
|
|
29
36
|
Money::Currency.register(currency_options)
|
30
37
|
end
|
31
38
|
|
39
|
+
def set_amount_column_for_default_currency!
|
40
|
+
amount_column.merge! postfix: "_#{default_currency.subunit.downcase.pluralize}" if default_currency.subunit
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_currency_column_for_default_currency!
|
44
|
+
iso_code = default_currency.iso_code
|
45
|
+
currency_column.merge! default: iso_code
|
46
|
+
end
|
47
|
+
|
32
48
|
# Set default bank object
|
33
49
|
#
|
34
50
|
# example (given that eu_central_bank is in Gemfile):
|
@@ -50,5 +66,12 @@ module MoneyRails
|
|
50
66
|
|
51
67
|
mattr_accessor :currency_column
|
52
68
|
@@currency_column = { postfix: '_currency', type: :string, null: false, default: 'USD', present: true }
|
69
|
+
|
70
|
+
# Use nil values to ignore defaults
|
71
|
+
mattr_accessor :no_cents_if_whole
|
72
|
+
@@no_cents_if_whole = nil
|
73
|
+
|
74
|
+
mattr_accessor :symbol
|
75
|
+
@@symbol = nil
|
53
76
|
end
|
54
77
|
end
|
@@ -5,32 +5,47 @@ module MoneyRails
|
|
5
5
|
content_tag(:span, Money.default_currency.symbol, :class => "currency_symbol")
|
6
6
|
end
|
7
7
|
|
8
|
-
def humanized_money(value,
|
8
|
+
def humanized_money(value, options={})
|
9
|
+
if !options || !options.is_a?(Hash)
|
10
|
+
warn "humanized_money now takes a hash of formatting options, please specify { :symbol => true }"
|
11
|
+
options = { :symbol => options }
|
12
|
+
end
|
13
|
+
|
14
|
+
options = {
|
15
|
+
:no_cents_if_whole => true,
|
16
|
+
:symbol => false
|
17
|
+
}.merge(options)
|
18
|
+
|
9
19
|
if value.is_a?(Money)
|
10
|
-
value.format(
|
20
|
+
value.format(options)
|
11
21
|
elsif value.respond_to?(:to_money)
|
12
|
-
value.to_money.format(
|
22
|
+
value.to_money.format(options)
|
13
23
|
else
|
14
24
|
""
|
15
25
|
end
|
16
26
|
end
|
17
27
|
|
18
28
|
def humanized_money_with_symbol(value)
|
19
|
-
humanized_money(value, true)
|
29
|
+
humanized_money(value, :symbol => true)
|
20
30
|
end
|
21
31
|
|
22
|
-
def money_without_cents(value,
|
23
|
-
if
|
24
|
-
|
25
|
-
|
26
|
-
value.to_money.format(:no_cents => true, :symbol => symbol)
|
27
|
-
else
|
28
|
-
""
|
32
|
+
def money_without_cents(value, options={})
|
33
|
+
if !options || !options.is_a?(Hash)
|
34
|
+
warn "money_without_cents now takes a hash of formatting options, please specify { :symbol => true }"
|
35
|
+
options = { :symbol => options }
|
29
36
|
end
|
37
|
+
|
38
|
+
options = {
|
39
|
+
:no_cents => true,
|
40
|
+
:no_cents_if_whole => false,
|
41
|
+
:symbol => false
|
42
|
+
}.merge(options)
|
43
|
+
|
44
|
+
humanized_money(value, options)
|
30
45
|
end
|
31
46
|
|
32
47
|
def money_without_cents_and_with_symbol(value)
|
33
|
-
money_without_cents(value, true)
|
48
|
+
money_without_cents(value, :symbol => true)
|
34
49
|
end
|
35
50
|
end
|
36
51
|
end
|
data/lib/money-rails/hooks.rb
CHANGED
@@ -18,10 +18,8 @@ module MoneyRails
|
|
18
18
|
if defined? ::Mongoid
|
19
19
|
if ::Mongoid::VERSION =~ /^2(.*)/
|
20
20
|
require 'money-rails/mongoid/two' # Loading the file is enough
|
21
|
-
|
22
|
-
|
23
|
-
if ::Mongoid::VERSION =~ /^3(.*)/
|
24
|
-
require 'money-rails/mongoid/three'
|
21
|
+
else
|
22
|
+
require 'money-rails/mongoid/money'
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|