custom_fields 2.12.1 → 2.13.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/MIT-LICENSE +1 -1
- data/README.md +4 -5
- data/lib/custom_fields/extensions/active_support.rb +22 -23
- data/lib/custom_fields/extensions/carrierwave.rb +9 -40
- data/lib/custom_fields/extensions/mongoid/association/referenced/has_many.rb +49 -0
- data/lib/custom_fields/extensions/mongoid/association/referenced/has_one.rb +17 -0
- data/lib/custom_fields/extensions/mongoid/association/relatable.rb +30 -0
- data/lib/custom_fields/extensions/mongoid/criteria/queryable/smash.rb +3 -6
- data/lib/custom_fields/extensions/mongoid/document.rb +4 -8
- data/lib/custom_fields/extensions/mongoid/factory.rb +7 -9
- data/lib/custom_fields/extensions/mongoid/fields/i18n.rb +17 -17
- data/lib/custom_fields/extensions/mongoid/fields/localized.rb +21 -21
- data/lib/custom_fields/extensions/mongoid/fields.rb +4 -7
- data/lib/custom_fields/extensions/mongoid/validatable/collection_size.rb +86 -0
- data/lib/custom_fields/extensions/mongoid/{validations → validatable}/macros.rb +3 -2
- data/lib/custom_fields/extensions/origin/smash.rb +4 -5
- data/lib/custom_fields/field.rb +39 -36
- data/lib/custom_fields/source.rb +46 -44
- data/lib/custom_fields/target.rb +11 -12
- data/lib/custom_fields/target_helpers.rb +21 -23
- data/lib/custom_fields/types/belongs_to.rb +6 -20
- data/lib/custom_fields/types/boolean.rb +5 -12
- data/lib/custom_fields/types/color.rb +4 -12
- data/lib/custom_fields/types/date.rb +20 -22
- data/lib/custom_fields/types/date_time.rb +16 -18
- data/lib/custom_fields/types/default.rb +16 -24
- data/lib/custom_fields/types/email.rb +6 -13
- data/lib/custom_fields/types/file.rb +26 -35
- data/lib/custom_fields/types/float.rb +10 -13
- data/lib/custom_fields/types/has_many.rb +12 -16
- data/lib/custom_fields/types/integer.rb +10 -13
- data/lib/custom_fields/types/json.rb +18 -29
- data/lib/custom_fields/types/many_to_many.rb +14 -19
- data/lib/custom_fields/types/money.rb +34 -35
- data/lib/custom_fields/types/password.rb +19 -23
- data/lib/custom_fields/types/relationship_default.rb +4 -16
- data/lib/custom_fields/types/select.rb +43 -51
- data/lib/custom_fields/types/string.rb +5 -13
- data/lib/custom_fields/types/tags.rb +11 -11
- data/lib/custom_fields/types/text.rb +4 -16
- data/lib/custom_fields/version.rb +4 -2
- data/lib/custom_fields.rb +16 -16
- metadata +38 -38
- data/lib/custom_fields/extensions/mongoid/relations/options.rb +0 -19
- data/lib/custom_fields/extensions/mongoid/relations/referenced/in.rb +0 -18
- data/lib/custom_fields/extensions/mongoid/relations/referenced/many.rb +0 -30
- data/lib/custom_fields/extensions/mongoid/validations/collection_size.rb +0 -43
@@ -1,17 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'English'
|
4
|
+
module CustomFields
|
3
5
|
module Types
|
4
|
-
|
5
6
|
module Json
|
6
|
-
|
7
7
|
module Field; end
|
8
8
|
|
9
9
|
module Target
|
10
|
-
|
11
10
|
extend ActiveSupport::Concern
|
12
11
|
|
13
12
|
module ClassMethods
|
14
|
-
|
15
13
|
# Adds a json field
|
16
14
|
#
|
17
15
|
# @param [ Class ] klass The class to modify
|
@@ -39,7 +37,7 @@ module CustomFields
|
|
39
37
|
# @return [ Hash ] field name => JSON
|
40
38
|
#
|
41
39
|
def json_attribute_get(instance, name)
|
42
|
-
|
40
|
+
default_attribute_get(instance, name)
|
43
41
|
end
|
44
42
|
|
45
43
|
# Set the value for the instance and the date field specified by
|
@@ -50,44 +48,35 @@ module CustomFields
|
|
50
48
|
# @param [ Hash ] attributes The attributes used to fetch the values
|
51
49
|
#
|
52
50
|
def json_attribute_set(instance, name, attributes)
|
53
|
-
|
51
|
+
default_attribute_set(instance, name, attributes)
|
54
52
|
end
|
55
|
-
|
56
53
|
end
|
57
54
|
|
58
55
|
protected
|
59
56
|
|
60
57
|
def decode_json(name, json)
|
61
|
-
|
62
|
-
|
63
|
-
value = nil if json.blank?
|
58
|
+
value = json.respond_to?(:to_str) && !json.blank? ? ActiveSupport::JSON.decode(URI.decode_www_form_component(json)) : json
|
59
|
+
value = nil if json.blank?
|
64
60
|
|
65
|
-
|
66
|
-
|
67
|
-
raise ActiveSupport::JSON.parse_error.new('Only a Hash object is accepted')
|
68
|
-
end
|
61
|
+
# Only hashes are accepted
|
62
|
+
raise ActiveSupport::JSON.parse_error, 'Only a Hash object is accepted' if value && !value.is_a?(Hash)
|
69
63
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
64
|
+
instance_variable_set(:"@#{name}_json_parsing_error", nil)
|
65
|
+
value
|
66
|
+
rescue ActiveSupport::JSON.parse_error
|
67
|
+
instance_variable_set(:"@#{name}_json_parsing_error", $ERROR_INFO.message)
|
68
|
+
nil
|
76
69
|
end
|
77
70
|
|
78
71
|
def add_json_parsing_error(name)
|
79
72
|
error = instance_variable_get(:"@#{name}_json_parsing_error")
|
80
73
|
|
81
|
-
|
82
|
-
msg = "Invalid #{name}: \"#{error}\". Check it out on http://jsonlint.com"
|
83
|
-
self.errors.add(name, msg)
|
84
|
-
end
|
85
|
-
end
|
74
|
+
return unless error
|
86
75
|
|
76
|
+
msg = "Invalid #{name}: \"#{error}\". Check it out on http://jsonlint.com"
|
77
|
+
errors.add(name, msg)
|
78
|
+
end
|
87
79
|
end
|
88
|
-
|
89
80
|
end
|
90
|
-
|
91
81
|
end
|
92
|
-
|
93
82
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CustomFields
|
2
4
|
module Types
|
3
5
|
module ManyToMany
|
@@ -6,11 +8,11 @@ module CustomFields
|
|
6
8
|
|
7
9
|
included do
|
8
10
|
def many_to_many_to_recipe
|
9
|
-
{ 'class_name' =>
|
11
|
+
{ 'class_name' => class_name, 'inverse_of' => inverse_of, 'order_by' => order_by }
|
10
12
|
end
|
11
13
|
|
12
14
|
def many_to_many_is_relationship?
|
13
|
-
|
15
|
+
type == 'many_to_many'
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -19,7 +21,6 @@ module CustomFields
|
|
19
21
|
extend ActiveSupport::Concern
|
20
22
|
|
21
23
|
module ClassMethods
|
22
|
-
|
23
24
|
# Adds a many_to_many relationship between 2 mongoid models
|
24
25
|
#
|
25
26
|
# @param [ Class ] klass The class to modify
|
@@ -28,10 +29,10 @@ module CustomFields
|
|
28
29
|
def apply_many_to_many_custom_field(klass, rule)
|
29
30
|
# puts "#{klass.inspect}.many_to_many #{rule['name'].inspect}, class_name: #{rule['class_name'].inspect} / #{rule['order_by']}" # DEBUG
|
30
31
|
|
31
|
-
klass.has_and_belongs_to_many rule['name'], class_name: rule['class_name'], inverse_of: rule['inverse_of'],
|
32
|
-
|
32
|
+
klass.has_and_belongs_to_many rule['name'], class_name: rule['class_name'], inverse_of: rule['inverse_of'],
|
33
|
+
validate: false, order: rule['order_by'] do
|
33
34
|
def filtered(conditions = {}, order_by = nil)
|
34
|
-
list = conditions.empty? ? self :
|
35
|
+
list = conditions.empty? ? self : where(conditions)
|
35
36
|
|
36
37
|
if order_by
|
37
38
|
list.order_by(order_by)
|
@@ -40,17 +41,17 @@ module CustomFields
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
+
alias_method :ordered, :filtered # backward compatibility + semantic purpose
|
44
45
|
|
45
|
-
def _naturally_ordered(criteria,
|
46
|
+
def _naturally_ordered(criteria, _order_by = nil)
|
46
47
|
# use the natural order given by the initial array (ex: project_ids).
|
47
48
|
# Warning: it returns an array and not a criteria object meaning it breaks the chain
|
48
|
-
ids =
|
49
|
+
ids = _base.send(_association.name.to_sym)
|
49
50
|
criteria.entries.sort { |a, b| ids.index(a.id) <=> ids.index(b.id) }
|
50
51
|
end
|
51
52
|
|
52
53
|
def pluck_with_natural_order(*attributes)
|
53
|
-
criteria =
|
54
|
+
criteria = only([:_id] + [*attributes])
|
54
55
|
_naturally_ordered(criteria).map do |entry|
|
55
56
|
if attributes.size == 1
|
56
57
|
entry.public_send(attributes.first.to_sym)
|
@@ -59,20 +60,14 @@ module CustomFields
|
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
62
|
-
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
klass.validates_collection_size_of rule['name'], minimum: 1, message: :at_least_one_element
|
67
|
-
end
|
68
|
-
end
|
65
|
+
return unless rule['required']
|
69
66
|
|
67
|
+
klass.validates_collection_size_of rule['name'], minimum: 1, message: :at_least_one_element
|
68
|
+
end
|
70
69
|
end
|
71
|
-
|
72
70
|
end
|
73
|
-
|
74
71
|
end
|
75
|
-
|
76
72
|
end
|
77
|
-
|
78
73
|
end
|
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
1
5
|
module CustomFields
|
2
6
|
module Types
|
3
7
|
module Money
|
4
|
-
|
5
8
|
module Field
|
6
9
|
extend ActiveSupport::Concern
|
7
10
|
|
@@ -10,7 +13,7 @@ module CustomFields
|
|
10
13
|
# to provide another currency instead of the the default
|
11
14
|
# e.g. default is 'EUR' and User sets '100.11 USD'
|
12
15
|
field :default_currency
|
13
|
-
field :allow_currency_from_symbol, type:
|
16
|
+
field :allow_currency_from_symbol, type: 'Boolean', default: false
|
14
17
|
|
15
18
|
before_validation :set_default
|
16
19
|
|
@@ -23,26 +26,22 @@ module CustomFields
|
|
23
26
|
def check_currency
|
24
27
|
::Money::Currency.find(self.default_currency)
|
25
28
|
end
|
26
|
-
|
27
|
-
end # included
|
29
|
+
end
|
28
30
|
|
29
31
|
def money_to_recipe
|
30
32
|
{ 'default_currency' => self.default_currency,
|
31
|
-
'allow_currency_from_symbol' =>
|
33
|
+
'allow_currency_from_symbol' => allow_currency_from_symbol }
|
32
34
|
end
|
33
35
|
|
34
|
-
def money_as_json(
|
36
|
+
def money_as_json(_options = {})
|
35
37
|
money_to_recipe
|
36
38
|
end
|
37
|
-
|
38
|
-
end # module Field
|
39
|
-
|
39
|
+
end
|
40
40
|
|
41
41
|
module Target
|
42
42
|
extend ActiveSupport::Concern
|
43
43
|
|
44
44
|
module ClassMethods
|
45
|
-
|
46
45
|
# Adds a Money field
|
47
46
|
#
|
48
47
|
# uses the money gem (https://github.com/RubyMoney/money)
|
@@ -54,16 +53,15 @@ module CustomFields
|
|
54
53
|
# and the currency
|
55
54
|
|
56
55
|
def apply_money_custom_field(klass, rule)
|
57
|
-
|
58
56
|
# the field names
|
59
57
|
name = rule['name']
|
60
58
|
names = {
|
61
|
-
name:
|
62
|
-
cents_field:
|
63
|
-
currency_field:
|
64
|
-
formatted_name_field:
|
59
|
+
name: name.to_sym,
|
60
|
+
cents_field: "#{name}_cents".to_sym,
|
61
|
+
currency_field: "#{name}_currency".to_sym,
|
62
|
+
formatted_name_field: "formatted_#{name}".to_sym,
|
65
63
|
allow_currency_from_symbol: "#{name}_allow_currency_from_symbol".to_sym,
|
66
|
-
default_currency:
|
64
|
+
default_currency: "#{name}_default_currency".to_sym
|
67
65
|
}
|
68
66
|
|
69
67
|
# fields
|
@@ -84,7 +82,6 @@ module CustomFields
|
|
84
82
|
klass.validate { _check_money(names) } if rule['required']
|
85
83
|
klass.validates_presence_of(names[:cents_field], names[:currency_field]) if rule['required']
|
86
84
|
klass.validates_numericality_of names[:cents_field], only_integer: true, if: names[:cents_field]
|
87
|
-
|
88
85
|
end
|
89
86
|
|
90
87
|
def money_attribute_get(instance, name)
|
@@ -95,51 +92,53 @@ module CustomFields
|
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
98
|
-
|
95
|
+
def money_attribute_set(instance, name, attributes)
|
99
96
|
return unless attributes.key?(name) || attributes.key?("formatted_#{name}")
|
97
|
+
|
100
98
|
value = attributes[name] || attributes["formatted_#{name}"]
|
101
99
|
instance.send(:"formatted_#{name}=", value)
|
102
100
|
end
|
103
|
-
|
104
|
-
|
105
101
|
end
|
106
102
|
|
107
103
|
protected
|
108
104
|
|
109
105
|
def _set_money_defaults(names)
|
110
|
-
::Monetize.assume_from_symbol =
|
111
|
-
::Money.default_currency =
|
106
|
+
::Monetize.assume_from_symbol = send(names[:allow_currency_from_symbol])
|
107
|
+
::Money.default_currency = send(names[:default_currency])
|
112
108
|
end
|
113
109
|
|
114
110
|
def _get_money(names)
|
115
111
|
_set_money_defaults(names)
|
116
|
-
::Money.new(
|
112
|
+
::Money.new(read_attribute(names[:cents_field]),
|
113
|
+
read_attribute(names[:currency_field]) || ::Money.default_currency)
|
117
114
|
end
|
118
115
|
|
119
116
|
def _check_money(names)
|
120
|
-
if [nil, ''].include?
|
121
|
-
|
122
|
-
end
|
117
|
+
raise ArgumentError, 'Unrecognized amount' if [nil, ''].include? read_attribute.names[:cents_field]
|
118
|
+
|
123
119
|
_get_money(names)
|
124
|
-
rescue
|
125
|
-
|
120
|
+
rescue StandardError
|
121
|
+
errors.add(names[:name], $ERROR_INFO.to_s)
|
126
122
|
false
|
127
123
|
end
|
128
124
|
|
129
125
|
def _set_money(_money, names)
|
130
126
|
return if _money.blank?
|
127
|
+
|
131
128
|
_set_money_defaults(names)
|
132
|
-
money = _money.
|
133
|
-
|
134
|
-
|
135
|
-
rescue
|
136
|
-
|
129
|
+
money = _money.is_a?(Money) ? _money : ::Monetize.parse(_money)
|
130
|
+
write_attribute(names[:cents_field], money.cents)
|
131
|
+
write_attribute(names[:currency_field], money.currency.iso_code)
|
132
|
+
rescue StandardError
|
133
|
+
errors.add(names[:name], $ERROR_INFO.to_s)
|
137
134
|
end
|
138
135
|
|
139
136
|
def _get_formatted_money(names)
|
140
|
-
_get_money(names).format(symbol:
|
137
|
+
_get_money(names).format(symbol: send(names[:allow_currency_from_symbol]),
|
138
|
+
no_cents_if_whole: true)
|
139
|
+
rescue StandardError
|
140
|
+
nil
|
141
141
|
end
|
142
|
-
|
143
142
|
end
|
144
143
|
end
|
145
144
|
end
|
@@ -1,25 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CustomFields
|
2
4
|
module Types
|
3
5
|
module Password
|
4
|
-
|
5
6
|
module Field
|
6
|
-
|
7
7
|
MIN_PASSWORD_LENGTH = 6
|
8
|
-
|
9
8
|
end
|
10
9
|
|
11
10
|
module Target
|
12
11
|
extend ActiveSupport::Concern
|
13
12
|
|
14
13
|
module ClassMethods
|
15
|
-
|
16
14
|
# Add a password field
|
17
15
|
#
|
18
16
|
# @param [ Class ] klass The class to modify
|
19
17
|
# @param [ Hash ] rule It contains the name of the field and if it is required or not
|
20
18
|
#
|
21
19
|
def apply_password_custom_field(klass, rule)
|
22
|
-
label
|
20
|
+
label = rule['label']
|
21
|
+
name = rule['name']
|
23
22
|
|
24
23
|
klass.field :"#{name}_hash"
|
25
24
|
|
@@ -39,7 +38,7 @@ module CustomFields
|
|
39
38
|
#
|
40
39
|
# @return [ Hash ] field name => raw value
|
41
40
|
#
|
42
|
-
def password_attribute_get(
|
41
|
+
def password_attribute_get(_instance, _name)
|
43
42
|
{}
|
44
43
|
end
|
45
44
|
|
@@ -53,38 +52,35 @@ module CustomFields
|
|
53
52
|
def password_attribute_set(instance, name, attributes)
|
54
53
|
instance._encrypt_password(name, attributes[name])
|
55
54
|
end
|
56
|
-
|
57
|
-
end # ClassMethods
|
55
|
+
end
|
58
56
|
|
59
57
|
def _set_confirmation_password(name, confirmation)
|
60
|
-
|
58
|
+
instance_variable_set(:"@#{name}_confirmation", confirmation)
|
61
59
|
end
|
62
60
|
|
63
61
|
def _encrypt_password(name, new_password)
|
64
62
|
return if new_password.blank?
|
65
63
|
|
66
|
-
|
64
|
+
instance_variable_set(:"@#{name}", new_password)
|
67
65
|
|
68
|
-
|
66
|
+
send(:"#{name}_hash=", BCrypt::Password.create(new_password))
|
69
67
|
end
|
70
68
|
|
71
69
|
def _check_password(label, name)
|
72
|
-
new_password =
|
73
|
-
confirmation =
|
70
|
+
new_password = instance_variable_get(:"@#{name}")
|
71
|
+
confirmation = instance_variable_get(:"@#{name}_confirmation")
|
74
72
|
|
75
73
|
return if new_password.blank?
|
76
74
|
|
77
75
|
if new_password.size < CustomFields::Types::Password::Field::MIN_PASSWORD_LENGTH
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
if confirmation && confirmation != new_password
|
82
|
-
self.errors.add("#{name}_confirmation", :confirmation, attribute: label || name)
|
76
|
+
errors.add(name, :too_short, count: CustomFields::Types::Password::Field::MIN_PASSWORD_LENGTH)
|
83
77
|
end
|
84
|
-
end
|
85
78
|
|
86
|
-
|
79
|
+
return unless confirmation && confirmation != new_password
|
87
80
|
|
88
|
-
|
89
|
-
|
90
|
-
end
|
81
|
+
errors.add("#{name}_confirmation", :confirmation, attribute: label || name)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -1,15 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
module Types
|
4
|
-
|
5
5
|
module RelationshipDefault
|
6
|
-
|
7
6
|
module Field
|
8
|
-
|
9
7
|
extend ActiveSupport::Concern
|
10
8
|
|
11
9
|
included do
|
12
|
-
|
13
10
|
field :class_name
|
14
11
|
field :inverse_of
|
15
12
|
field :order_by
|
@@ -18,8 +15,8 @@ module CustomFields
|
|
18
15
|
validate :ensure_class_name_security, if: :is_relationship?
|
19
16
|
|
20
17
|
def is_relationship?
|
21
|
-
method_name = :"#{
|
22
|
-
|
18
|
+
method_name = :"#{type}_is_relationship?"
|
19
|
+
respond_to?(method_name) && send(method_name)
|
23
20
|
end
|
24
21
|
|
25
22
|
protected
|
@@ -28,17 +25,8 @@ module CustomFields
|
|
28
25
|
true
|
29
26
|
# FIXME: to be overridden in the target application
|
30
27
|
end
|
31
|
-
|
32
28
|
end
|
33
|
-
|
34
29
|
end
|
35
|
-
|
36
30
|
end
|
37
|
-
|
38
31
|
end
|
39
|
-
|
40
32
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|