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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +4 -5
  4. data/lib/custom_fields/extensions/active_support.rb +22 -23
  5. data/lib/custom_fields/extensions/carrierwave.rb +9 -40
  6. data/lib/custom_fields/extensions/mongoid/association/referenced/has_many.rb +49 -0
  7. data/lib/custom_fields/extensions/mongoid/association/referenced/has_one.rb +17 -0
  8. data/lib/custom_fields/extensions/mongoid/association/relatable.rb +30 -0
  9. data/lib/custom_fields/extensions/mongoid/criteria/queryable/smash.rb +3 -6
  10. data/lib/custom_fields/extensions/mongoid/document.rb +4 -8
  11. data/lib/custom_fields/extensions/mongoid/factory.rb +7 -9
  12. data/lib/custom_fields/extensions/mongoid/fields/i18n.rb +17 -17
  13. data/lib/custom_fields/extensions/mongoid/fields/localized.rb +21 -21
  14. data/lib/custom_fields/extensions/mongoid/fields.rb +4 -7
  15. data/lib/custom_fields/extensions/mongoid/validatable/collection_size.rb +86 -0
  16. data/lib/custom_fields/extensions/mongoid/{validations → validatable}/macros.rb +3 -2
  17. data/lib/custom_fields/extensions/origin/smash.rb +4 -5
  18. data/lib/custom_fields/field.rb +39 -36
  19. data/lib/custom_fields/source.rb +46 -44
  20. data/lib/custom_fields/target.rb +11 -12
  21. data/lib/custom_fields/target_helpers.rb +21 -23
  22. data/lib/custom_fields/types/belongs_to.rb +6 -20
  23. data/lib/custom_fields/types/boolean.rb +5 -12
  24. data/lib/custom_fields/types/color.rb +4 -12
  25. data/lib/custom_fields/types/date.rb +20 -22
  26. data/lib/custom_fields/types/date_time.rb +16 -18
  27. data/lib/custom_fields/types/default.rb +16 -24
  28. data/lib/custom_fields/types/email.rb +6 -13
  29. data/lib/custom_fields/types/file.rb +26 -35
  30. data/lib/custom_fields/types/float.rb +10 -13
  31. data/lib/custom_fields/types/has_many.rb +12 -16
  32. data/lib/custom_fields/types/integer.rb +10 -13
  33. data/lib/custom_fields/types/json.rb +18 -29
  34. data/lib/custom_fields/types/many_to_many.rb +14 -19
  35. data/lib/custom_fields/types/money.rb +34 -35
  36. data/lib/custom_fields/types/password.rb +19 -23
  37. data/lib/custom_fields/types/relationship_default.rb +4 -16
  38. data/lib/custom_fields/types/select.rb +43 -51
  39. data/lib/custom_fields/types/string.rb +5 -13
  40. data/lib/custom_fields/types/tags.rb +11 -11
  41. data/lib/custom_fields/types/text.rb +4 -16
  42. data/lib/custom_fields/version.rb +4 -2
  43. data/lib/custom_fields.rb +16 -16
  44. metadata +38 -38
  45. data/lib/custom_fields/extensions/mongoid/relations/options.rb +0 -19
  46. data/lib/custom_fields/extensions/mongoid/relations/referenced/in.rb +0 -18
  47. data/lib/custom_fields/extensions/mongoid/relations/referenced/many.rb +0 -30
  48. data/lib/custom_fields/extensions/mongoid/validations/collection_size.rb +0 -43
@@ -1,17 +1,15 @@
1
- module CustomFields
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
- self.default_attribute_get(instance, name)
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
- self.default_attribute_set(instance, name, attributes)
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
- begin
62
- value = json.respond_to?(:to_str) && !json.blank? ? ActiveSupport::JSON.decode(URI.unescape(json)) : json
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
- # Only hashes are accepted
66
- if value && !value.is_a?(Hash)
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
- instance_variable_set(:"@#{name}_json_parsing_error", nil)
71
- value
72
- rescue ActiveSupport::JSON.parse_error
73
- instance_variable_set(:"@#{name}_json_parsing_error", $!.message)
74
- nil
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
- if error
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' => self.class_name, 'inverse_of' => self.inverse_of, 'order_by' => self.order_by }
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
- self.type == 'many_to_many'
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'], validate: false, order: rule['order_by'] do
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 : self.where(conditions)
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
- alias :ordered :filtered # backward compatibility + semantic purpose
44
+ alias_method :ordered, :filtered # backward compatibility + semantic purpose
44
45
 
45
- def _naturally_ordered(criteria, order_by = nil)
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 = base.send(relation_metadata.key.to_sym)
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 = self.only([:_id] + [*attributes])
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
- if rule['required']
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: ::Boolean, default: false
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' => self.allow_currency_from_symbol }
33
+ 'allow_currency_from_symbol' => allow_currency_from_symbol }
32
34
  end
33
35
 
34
- def money_as_json(options = {})
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: name.to_sym,
62
- cents_field: "#{name}_cents".to_sym,
63
- currency_field: "#{name}_currency".to_sym,
64
- formatted_name_field: "formatted_#{name}".to_sym,
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: "#{name}_default_currency".to_sym
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
- def money_attribute_set(instance, name, attributes)
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 = self.send(names[:allow_currency_from_symbol])
111
- ::Money.default_currency = self.send(names[: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(self.read_attribute(names[:cents_field]), self.read_attribute(names[:currency_field]) || ::Money.default_currency)
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? self.read_attribute.names[:cents_field]
121
- raise ArgumentError.new 'Unrecognized amount'
122
- end
117
+ raise ArgumentError, 'Unrecognized amount' if [nil, ''].include? read_attribute.names[:cents_field]
118
+
123
119
  _get_money(names)
124
- rescue
125
- self.errors.add(names[:name], "#{$!}")
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.kind_of?(Money) ? _money : ::Monetize.parse(_money)
133
- self.write_attribute(names[:cents_field], money.cents)
134
- self.write_attribute(names[:currency_field], money.currency.iso_code)
135
- rescue
136
- self.errors.add(names[:name], "#{$!}")
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: self.send(names[:allow_currency_from_symbol]), no_cents_if_whole: true) rescue nil
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, name = rule['label'], rule['name']
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(instance, name)
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
- self.instance_variable_set(:"@#{name}_confirmation", confirmation)
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
- self.instance_variable_set(:"@#{name}", new_password)
64
+ instance_variable_set(:"@#{name}", new_password)
67
65
 
68
- self.send(:"#{name}_hash=", BCrypt::Password.create(new_password))
66
+ send(:"#{name}_hash=", BCrypt::Password.create(new_password))
69
67
  end
70
68
 
71
69
  def _check_password(label, name)
72
- new_password = self.instance_variable_get(:"@#{name}")
73
- confirmation = self.instance_variable_get(:"@#{name}_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
- self.errors.add(name, :too_short, count: CustomFields::Types::Password::Field::MIN_PASSWORD_LENGTH)
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
- end # Target
79
+ return unless confirmation && confirmation != new_password
87
80
 
88
- end # Password
89
- end # Types
90
- end # CustomFields
81
+ errors.add("#{name}_confirmation", :confirmation, attribute: label || name)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,15 +1,12 @@
1
- module CustomFields
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 = :"#{self.type}_is_relationship?"
22
- self.respond_to?(method_name) && self.send(method_name)
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
-