custom_fields 2.12.1 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
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
-