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
data/lib/custom_fields/field.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
class Field
|
4
|
-
|
5
5
|
include ::Mongoid::Document
|
6
6
|
include ::Mongoid::Timestamps
|
7
7
|
|
8
|
-
AVAILABLE_TYPES = %w
|
9
|
-
|
8
|
+
AVAILABLE_TYPES = %w[default string text email date date_time boolean file select float integer
|
9
|
+
money tags color relationship_default belongs_to has_many many_to_many password json].freeze
|
10
10
|
|
11
11
|
## types ##
|
12
12
|
AVAILABLE_TYPES.each do |type|
|
@@ -19,14 +19,14 @@ module CustomFields
|
|
19
19
|
field :type
|
20
20
|
field :hint
|
21
21
|
field :position, type: ::Integer, default: 0
|
22
|
-
field :required, type:
|
23
|
-
field :unique, type:
|
24
|
-
field :localized, type:
|
22
|
+
field :required, type: 'Boolean', default: false
|
23
|
+
field :unique, type: 'Boolean', default: false
|
24
|
+
field :localized, type: 'Boolean', default: false
|
25
25
|
field :default
|
26
26
|
|
27
27
|
## validations ##
|
28
28
|
validates_presence_of :label, :type
|
29
|
-
validates_exclusion_of :name, in:
|
29
|
+
validates_exclusion_of :name, in: ->(_f) { CustomFields.options[:reserved_names].map(&:to_s) }
|
30
30
|
validates_inclusion_of :type, in: AVAILABLE_TYPES, allow_blank: true
|
31
31
|
validates_format_of :name, with: /^[a-z]([A-Za-z0-9_]+)?$/, multiline: true
|
32
32
|
validate :uniqueness_of_label_and_name
|
@@ -45,10 +45,10 @@ module CustomFields
|
|
45
45
|
# @return [ Hash ] The memo object upgraded
|
46
46
|
#
|
47
47
|
def collect_diff(memo)
|
48
|
-
method_name = :"collect_#{
|
48
|
+
method_name = :"collect_#{type}_diff"
|
49
49
|
|
50
|
-
if
|
51
|
-
|
50
|
+
if respond_to?(method_name)
|
51
|
+
send(method_name, memo)
|
52
52
|
else
|
53
53
|
collect_default_diff(memo)
|
54
54
|
end
|
@@ -61,20 +61,28 @@ module CustomFields
|
|
61
61
|
# @return [ Hash ] The hash
|
62
62
|
#
|
63
63
|
def to_recipe
|
64
|
-
method_name = :"#{
|
65
|
-
custom_to_recipe =
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
'
|
64
|
+
method_name = :"#{type}_to_recipe"
|
65
|
+
custom_to_recipe = begin
|
66
|
+
send(method_name)
|
67
|
+
rescue StandardError
|
68
|
+
{}
|
69
|
+
end
|
70
|
+
|
71
|
+
{ 'name' => name,
|
72
|
+
'type' => type,
|
73
|
+
'required' => required?,
|
74
|
+
'unique' => unique?,
|
75
|
+
'localized' => localized?,
|
76
|
+
'default' => default }.merge(custom_to_recipe)
|
73
77
|
end
|
74
78
|
|
75
79
|
def as_json(options = {})
|
76
|
-
method_name = :"#{
|
77
|
-
custom_as_json =
|
80
|
+
method_name = :"#{type}_as_json"
|
81
|
+
custom_as_json = begin
|
82
|
+
send(method_name)
|
83
|
+
rescue StandardError
|
84
|
+
{}
|
85
|
+
end
|
78
86
|
|
79
87
|
super(options).merge(custom_as_json)
|
80
88
|
end
|
@@ -82,28 +90,23 @@ module CustomFields
|
|
82
90
|
protected
|
83
91
|
|
84
92
|
def uniqueness_of_label_and_name
|
85
|
-
if
|
86
|
-
self.errors.add(:label, :taken)
|
87
|
-
end
|
93
|
+
errors.add(:label, :taken) if siblings.any? { |f| f.label == label && f._id != _id }
|
88
94
|
|
89
|
-
|
90
|
-
|
91
|
-
|
95
|
+
return unless siblings.any? { |f| f.name == name && f._id != _id }
|
96
|
+
|
97
|
+
errors.add(:name, :taken)
|
92
98
|
end
|
93
99
|
|
94
100
|
def set_name
|
95
|
-
return if
|
101
|
+
return if label.blank? && name.blank?
|
96
102
|
|
97
|
-
|
98
|
-
|
99
|
-
|
103
|
+
return unless name.blank?
|
104
|
+
|
105
|
+
self.name = ActiveSupport::Inflector.parameterize(label, separator: '_').gsub('-', '_').downcase
|
100
106
|
end
|
101
107
|
|
102
108
|
def siblings
|
103
|
-
|
104
|
-
self._parent.send(self.relation_metadata.name)
|
109
|
+
_parent.send(association_name)
|
105
110
|
end
|
106
|
-
|
107
111
|
end
|
108
|
-
|
109
112
|
end
|
data/lib/custom_fields/source.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
module Source
|
4
|
-
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
@@ -35,9 +35,9 @@ module CustomFields
|
|
35
35
|
#
|
36
36
|
def klass_with_custom_fields(name)
|
37
37
|
# Rails.logger.debug "[CustomFields] klass_with_custom_fields #{self.send(name).metadata.klass} / #{self.send(name).metadata[:old_klass]}" if defined?(Rails) # DEBUG
|
38
|
-
recipe =
|
39
|
-
_metadata =
|
40
|
-
target = _metadata[:original_klass] || _metadata.klass # avoid to use an already enhanced klass
|
38
|
+
recipe = custom_fields_recipe_for(name)
|
39
|
+
_metadata = send(name)._association
|
40
|
+
target = _metadata.options[:original_klass] || _metadata.klass # avoid to use an already enhanced klass
|
41
41
|
target.klass_with_custom_fields(recipe)
|
42
42
|
end
|
43
43
|
|
@@ -51,7 +51,7 @@ module CustomFields
|
|
51
51
|
# @return [ Collection ] The ordered list.
|
52
52
|
#
|
53
53
|
def ordered_custom_fields(name)
|
54
|
-
|
54
|
+
send(:"#{name}_custom_fields").sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
55
55
|
end
|
56
56
|
|
57
57
|
# Returns the recipe (meaning all the rules) needed to
|
@@ -63,10 +63,10 @@ module CustomFields
|
|
63
63
|
#
|
64
64
|
def custom_fields_recipe_for(name)
|
65
65
|
{
|
66
|
-
'name'
|
67
|
-
'rules'
|
68
|
-
'version'
|
69
|
-
'model_name' =>
|
66
|
+
'name' => "#{relations[name.to_s].class_name.demodulize}#{_id}",
|
67
|
+
'rules' => ordered_custom_fields(name).map(&:to_recipe),
|
68
|
+
'version' => custom_fields_version(name),
|
69
|
+
'model_name' => relations[name.to_s].class_name.constantize.model_name.to_s
|
70
70
|
}
|
71
71
|
end
|
72
72
|
|
@@ -77,7 +77,7 @@ module CustomFields
|
|
77
77
|
# @return [ Integer ] The version number
|
78
78
|
#
|
79
79
|
def custom_fields_version(name)
|
80
|
-
|
80
|
+
send(:"#{name}_custom_fields_version") || 0
|
81
81
|
end
|
82
82
|
|
83
83
|
# When the fields have been modified and before the object is saved,
|
@@ -86,8 +86,8 @@ module CustomFields
|
|
86
86
|
# @param [ String, Symbol ] name The name of the relation.
|
87
87
|
#
|
88
88
|
def bump_custom_fields_version(name)
|
89
|
-
version =
|
90
|
-
|
89
|
+
version = custom_fields_version(name) + 1
|
90
|
+
send(:"#{name}_custom_fields_version=", version)
|
91
91
|
end
|
92
92
|
|
93
93
|
# Change the metadata of a relation enhanced by the custom fields.
|
@@ -96,21 +96,22 @@ module CustomFields
|
|
96
96
|
# @param [ String, Symbol ] name The name of the relation.
|
97
97
|
#
|
98
98
|
def refresh_metadata_with_custom_fields(name)
|
99
|
-
return if !
|
99
|
+
return if !persisted? || send(:"#{name}_custom_fields").blank?
|
100
100
|
|
101
|
-
old_metadata =
|
101
|
+
old_metadata = send(name)._association
|
102
102
|
|
103
103
|
# puts "old_metadata = #{old_metadata.klass.inspect} / #{old_metadata.object_id.inspect}" # DEBUG
|
104
104
|
|
105
105
|
# puts "[CustomFields] refresh_metadata_with_custom_fields, #{name.inspect}, self = #{self.inspect}"
|
106
106
|
|
107
|
-
|
107
|
+
send(name)._association = old_metadata.clone.tap do |metadata|
|
108
108
|
# Rails.logger.debug "[CustomFields] refresh_metadata_with_custom_fields #{metadata.klass}" if defined?(Rails) # DEBUG
|
109
109
|
|
110
110
|
# backup the current klass
|
111
|
-
metadata
|
111
|
+
metadata.instance_variable_set(:@options, metadata.options.dup)
|
112
|
+
metadata.options[:original_klass] ||= metadata.klass
|
112
113
|
|
113
|
-
metadata.instance_variable_set(:@klass,
|
114
|
+
metadata.instance_variable_set(:@klass, klass_with_custom_fields(name))
|
114
115
|
end
|
115
116
|
set_attribute_localization(name)
|
116
117
|
# puts "new_metadata = #{self.send(name).metadata.klass.inspect} / #{self.send(name).metadata.object_id.inspect}" # DEBUG
|
@@ -118,9 +119,9 @@ module CustomFields
|
|
118
119
|
|
119
120
|
def set_attribute_localization(name)
|
120
121
|
klass_name = name.singularize.to_sym
|
121
|
-
|
122
|
+
send(:"#{name}_custom_fields").each do |cf|
|
122
123
|
I18n.backend.store_translations ::I18n.locale,
|
123
|
-
|
124
|
+
{ mongoid: { attributes: { klass_name => { cf.name.to_sym => cf.label } } } }
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
@@ -145,7 +146,7 @@ module CustomFields
|
|
145
146
|
def collect_custom_fields_diff(name, fields)
|
146
147
|
# puts "==> collect_custom_fields_diff for #{name}, #{fields.size}" # DEBUG
|
147
148
|
|
148
|
-
memo =
|
149
|
+
memo = initialize_custom_fields_diff(name)
|
149
150
|
|
150
151
|
fields.map do |field|
|
151
152
|
field.collect_diff(memo)
|
@@ -169,12 +170,13 @@ module CustomFields
|
|
169
170
|
# puts "==> apply_custom_fields_recipes for #{name}, #{self._custom_fields_diff[name].inspect}" # DEBUG
|
170
171
|
|
171
172
|
operations = self._custom_fields_diff[name]
|
172
|
-
operations['$set'].merge!({ 'custom_fields_recipe.version' =>
|
173
|
-
collection
|
173
|
+
operations['$set'].merge!({ 'custom_fields_recipe.version' => custom_fields_version(name) })
|
174
|
+
collection = send(name).collection
|
175
|
+
selector = send(name).criteria.selector
|
174
176
|
|
175
177
|
# http://docs.mongodb.org/manual/reference/method/db.collection.update/#update-parameter
|
176
178
|
# The <update> document must contain only update operator expressions.
|
177
|
-
%w
|
179
|
+
%w[set unset rename].each do |operation_name|
|
178
180
|
_fields = operations.delete("$#{operation_name}")
|
179
181
|
|
180
182
|
next if _fields.empty?
|
@@ -195,31 +197,30 @@ module CustomFields
|
|
195
197
|
def apply_custom_fields_localize_diff(name)
|
196
198
|
return if self._custom_field_localize_diff[name].empty?
|
197
199
|
|
198
|
-
|
200
|
+
send(name).all.each do |record|
|
199
201
|
updates = {}
|
200
202
|
|
201
203
|
# puts "[apply_custom_fields_localize_diff] processing: record #{record._id} / #{self._custom_field_localize_diff[name].inspect}" # DEBUG
|
202
204
|
self._custom_field_localize_diff[name].each do |changes|
|
205
|
+
value = record.attributes[changes[:field]]
|
203
206
|
if changes[:localized]
|
204
|
-
value = record.read_attribute(changes[:field].to_sym)
|
205
207
|
updates[changes[:field]] = { Mongoid::Fields::I18n.locale.to_s => value }
|
206
208
|
else
|
207
209
|
# the other way around
|
208
|
-
value = record.read_attribute(changes[:field].to_sym)
|
209
210
|
next if value.nil?
|
211
|
+
|
210
212
|
updates[changes[:field]] = value[Mongoid::Fields::I18n.locale.to_s]
|
211
213
|
end
|
212
214
|
end
|
213
215
|
|
214
216
|
next if updates.empty?
|
215
217
|
|
216
|
-
collection =
|
218
|
+
collection = send(name).collection
|
217
219
|
collection.find(record.atomic_selector).update_one({ '$set' => updates })
|
218
220
|
end
|
219
221
|
end
|
220
222
|
|
221
223
|
module ClassMethods
|
222
|
-
|
223
224
|
# Determines if the relation is enhanced by the custom fields
|
224
225
|
#
|
225
226
|
# @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
|
@@ -230,7 +231,7 @@ module CustomFields
|
|
230
231
|
# @return [ true, false ] True if enhanced, false if not.
|
231
232
|
#
|
232
233
|
def custom_fields_for?(name)
|
233
|
-
|
234
|
+
_custom_fields_for.include?(name.to_s)
|
234
235
|
end
|
235
236
|
|
236
237
|
# Enhance a referenced collection OR the instance itself (by passing self) by providing methods to manage custom fields.
|
@@ -253,12 +254,12 @@ module CustomFields
|
|
253
254
|
# company.employees.build name: 'Michael Scott', position: 'Regional manager'
|
254
255
|
#
|
255
256
|
def custom_fields_for(name)
|
256
|
-
|
257
|
+
declare_embedded_in_definition_in_custom_field(name)
|
257
258
|
|
258
259
|
# stores the relation name
|
259
|
-
|
260
|
+
_custom_fields_for << name.to_s
|
260
261
|
|
261
|
-
|
262
|
+
extend_for_custom_fields(name)
|
262
263
|
end
|
263
264
|
|
264
265
|
protected
|
@@ -272,12 +273,12 @@ module CustomFields
|
|
272
273
|
class_eval do
|
273
274
|
field :"#{name}_custom_fields_version", type: ::Integer, default: 0
|
274
275
|
|
275
|
-
embeds_many :"#{name}_custom_fields", class_name:
|
276
|
+
embeds_many :"#{name}_custom_fields", class_name: dynamic_custom_field_class_name(name) # , cascade_callbacks: true # FIXME ?????
|
276
277
|
|
277
278
|
accepts_nested_attributes_for :"#{name}_custom_fields", allow_destroy: true
|
278
279
|
end
|
279
280
|
|
280
|
-
class_eval <<-EOV
|
281
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
281
282
|
after_initialize :refresh_#{name}_metadata
|
282
283
|
before_update :bump_#{name}_custom_fields_version
|
283
284
|
before_update :collect_#{name}_custom_fields_diff
|
@@ -334,21 +335,22 @@ module CustomFields
|
|
334
335
|
# @return [ Field ] The new field class.
|
335
336
|
#
|
336
337
|
def declare_embedded_in_definition_in_custom_field(name)
|
337
|
-
klass_name =
|
338
|
+
klass_name = dynamic_custom_field_class_name(name).split('::').last # Use only the class, ignore the modules
|
338
339
|
|
339
|
-
source =
|
340
|
+
source = safe_module_parents.size > 1 ? safe_module_parents.first : Object
|
340
341
|
|
341
|
-
|
342
|
-
|
342
|
+
return if source.const_defined?(klass_name)
|
343
|
+
|
344
|
+
(klass = Class.new(::CustomFields::Field)).class_eval <<-EOF, __FILE__, __LINE__ + 1
|
343
345
|
embedded_in :#{self.name.demodulize.underscore}, inverse_of: :#{name}_custom_fields, class_name: '#{self.name}'
|
344
|
-
|
346
|
+
EOF
|
345
347
|
|
346
|
-
|
347
|
-
end
|
348
|
+
source.const_set(klass_name, klass)
|
348
349
|
end
|
349
350
|
|
351
|
+
def safe_module_parents
|
352
|
+
respond_to?(:module_parents) ? module_parents : parents
|
353
|
+
end
|
350
354
|
end
|
351
|
-
|
352
355
|
end
|
353
|
-
|
354
356
|
end
|
data/lib/custom_fields/target.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
module Target
|
4
|
-
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
|
9
8
|
## types ##
|
10
|
-
%w
|
11
|
-
|
12
|
-
|
9
|
+
%w[default string text email date date_time boolean file select
|
10
|
+
float integer money color belongs_to has_many many_to_many
|
11
|
+
tags password json].each do |type|
|
13
12
|
include "CustomFields::Types::#{type.camelize}::Target".constantize
|
14
13
|
end
|
15
14
|
|
@@ -20,7 +19,6 @@ module CustomFields
|
|
20
19
|
end
|
21
20
|
|
22
21
|
module ClassMethods
|
23
|
-
|
24
22
|
# A document with custom fields always returns true.
|
25
23
|
#
|
26
24
|
# @return [ Boolean ] True
|
@@ -39,7 +37,7 @@ module CustomFields
|
|
39
37
|
def build_klass_with_custom_fields(recipe)
|
40
38
|
name = recipe['name']
|
41
39
|
# puts "CREATING #{name}, #{recipe.inspect}" # DEBUG
|
42
|
-
|
40
|
+
safe_module_parent.const_set(name, Class.new(self)).tap do |klass|
|
43
41
|
klass.cattr_accessor :version
|
44
42
|
|
45
43
|
klass.version = recipe['version']
|
@@ -49,10 +47,10 @@ module CustomFields
|
|
49
47
|
# klass.write_inheritable_attribute(:scopes, self.scopes)
|
50
48
|
|
51
49
|
recipe['rules'].each do |rule|
|
52
|
-
|
50
|
+
send(:"apply_#{rule['type']}_custom_field", klass, rule)
|
53
51
|
end
|
54
52
|
recipe_model_name = recipe['model_name']
|
55
|
-
model_name =
|
53
|
+
model_name = proc do
|
56
54
|
if recipe_model_name.is_a?(ActiveModel::Name)
|
57
55
|
recipe_model_name
|
58
56
|
else
|
@@ -93,8 +91,9 @@ module CustomFields
|
|
93
91
|
klass
|
94
92
|
end
|
95
93
|
|
94
|
+
def safe_module_parent
|
95
|
+
respond_to?(:module_parent) ? module_parent : parent
|
96
|
+
end
|
96
97
|
end
|
97
|
-
|
98
98
|
end
|
99
|
-
|
100
99
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
module TargetHelpers
|
4
|
-
|
5
5
|
# Return the list of the getters dynamically based on the
|
6
6
|
# custom_fields recipe in order to get the formatted values
|
7
7
|
# of the custom fields.
|
@@ -18,8 +18,8 @@ module CustomFields
|
|
18
18
|
# @return [ List ] a list of method names (string)
|
19
19
|
#
|
20
20
|
def custom_fields_methods(&filter)
|
21
|
-
|
22
|
-
method =
|
21
|
+
custom_fields_recipe['rules'].map do |rule|
|
22
|
+
method = custom_fields_getters_for rule['name'], rule['type']
|
23
23
|
if block_given?
|
24
24
|
filter.call(rule) ? method : nil
|
25
25
|
else
|
@@ -34,7 +34,7 @@ module CustomFields
|
|
34
34
|
# @return [ List ] a list of method names (string)
|
35
35
|
#
|
36
36
|
def custom_fields_safe_setters
|
37
|
-
|
37
|
+
custom_fields_recipe['rules'].map do |rule|
|
38
38
|
case rule['type'].to_sym
|
39
39
|
when :date, :date_time, :money then "formatted_#{rule['name']}"
|
40
40
|
when :file then [rule['name'], "remove_#{rule['name']}", "remote_#{rule['name']}_url"]
|
@@ -54,8 +54,9 @@ module CustomFields
|
|
54
54
|
#
|
55
55
|
def custom_fields_basic_attributes
|
56
56
|
{}.tap do |hash|
|
57
|
-
|
58
|
-
name
|
57
|
+
non_relationship_custom_fields.each do |rule|
|
58
|
+
name = rule['name']
|
59
|
+
type = rule['type'].to_sym
|
59
60
|
|
60
61
|
# method of the custom getter
|
61
62
|
method_name = "#{type}_attribute_get"
|
@@ -71,8 +72,9 @@ module CustomFields
|
|
71
72
|
# @param [ Hash ] The attributes for the custom fields and their related fields.
|
72
73
|
#
|
73
74
|
def custom_fields_basic_attributes=(attributes)
|
74
|
-
|
75
|
-
name
|
75
|
+
non_relationship_custom_fields.each do |rule|
|
76
|
+
name = rule['name']
|
77
|
+
type = rule['type'].to_sym
|
76
78
|
|
77
79
|
# method of the custom getter
|
78
80
|
method_name = "#{type}_attribute_set"
|
@@ -89,7 +91,7 @@ module CustomFields
|
|
89
91
|
# @return [ Boolean ] True if the rule is a "many" relationship kind.
|
90
92
|
#
|
91
93
|
def is_a_custom_field_many_relationship?(name)
|
92
|
-
rule =
|
94
|
+
rule = custom_fields_recipe['rules'].detect do |rule|
|
93
95
|
rule['name'] == name && _custom_field_many_relationship?(rule['type'])
|
94
96
|
end
|
95
97
|
end
|
@@ -99,8 +101,8 @@ module CustomFields
|
|
99
101
|
# @return [ Array ] List of rules (Hash)
|
100
102
|
#
|
101
103
|
def non_relationship_custom_fields
|
102
|
-
|
103
|
-
!%w
|
104
|
+
custom_fields_recipe['rules'].find_all do |rule|
|
105
|
+
!%w[belongs_to has_many many_to_many].include?(rule['type'])
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
@@ -109,8 +111,8 @@ module CustomFields
|
|
109
111
|
# @return [ Array ] List of rules (Hash)
|
110
112
|
#
|
111
113
|
def relationship_custom_fields
|
112
|
-
|
113
|
-
%w
|
114
|
+
custom_fields_recipe['rules'].find_all do |rule|
|
115
|
+
%w[belongs_to has_many many_to_many].include?(rule['type'])
|
114
116
|
end
|
115
117
|
end
|
116
118
|
|
@@ -173,20 +175,16 @@ module CustomFields
|
|
173
175
|
end
|
174
176
|
end
|
175
177
|
|
176
|
-
|
178
|
+
# :nodoc:
|
177
179
|
def _custom_field_many_relationship?(type)
|
178
|
-
%w
|
180
|
+
%w[has_many many_to_many].include?(type)
|
179
181
|
end
|
180
182
|
|
181
|
-
|
183
|
+
# :nodoc:
|
182
184
|
def group_custom_fields(type, &block)
|
183
|
-
unless block_given?
|
184
|
-
block = lambda { |rule| rule['name'] }
|
185
|
-
end
|
185
|
+
block = ->(rule) { rule['name'] } unless block_given?
|
186
186
|
|
187
|
-
|
187
|
+
custom_fields_recipe['rules'].find_all { |rule| rule['type'] == type }.map(&block)
|
188
188
|
end
|
189
|
-
|
190
189
|
end
|
191
|
-
|
192
190
|
end
|
@@ -1,33 +1,26 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
module Types
|
4
|
-
|
5
5
|
module BelongsTo
|
6
|
-
|
7
6
|
module Field
|
8
|
-
|
9
7
|
extend ActiveSupport::Concern
|
10
8
|
|
11
9
|
included do
|
12
|
-
|
13
10
|
def belongs_to_to_recipe
|
14
|
-
{ 'class_name' =>
|
11
|
+
{ 'class_name' => class_name, 'inverse_of' => inverse_of }
|
15
12
|
end
|
16
13
|
|
17
14
|
def belongs_to_is_relationship?
|
18
|
-
|
15
|
+
type == 'belongs_to'
|
19
16
|
end
|
20
|
-
|
21
17
|
end
|
22
|
-
|
23
18
|
end
|
24
19
|
|
25
20
|
module Target
|
26
|
-
|
27
21
|
extend ActiveSupport::Concern
|
28
22
|
|
29
23
|
module ClassMethods
|
30
|
-
|
31
24
|
# Adds a belongs_to relationship between 2 models
|
32
25
|
#
|
33
26
|
# @param [ Class ] klass The class to modify
|
@@ -43,26 +36,19 @@ module CustomFields
|
|
43
36
|
klass.field position_name, type: ::Integer, default: 0
|
44
37
|
|
45
38
|
options = { class_name: rule['class_name'], optional: true }
|
46
|
-
options[:inverse_of] = rule['inverse_of'] unless rule['inverse_of'].blank?
|
39
|
+
options[:inverse_of] = rule['inverse_of'] unless rule['inverse_of'].blank?
|
47
40
|
|
48
41
|
klass.belongs_to rule['name'].to_sym, options
|
49
42
|
|
50
|
-
if rule['required']
|
51
|
-
klass.validates_presence_of rule['name'].to_sym
|
52
|
-
end
|
43
|
+
klass.validates_presence_of rule['name'].to_sym if rule['required']
|
53
44
|
|
54
45
|
klass.before_create do |object|
|
55
46
|
position = (object.class.max(position_name.to_sym) || 0) + 1
|
56
47
|
object.send(:"#{position_name}=", position)
|
57
48
|
end
|
58
49
|
end
|
59
|
-
|
60
50
|
end
|
61
|
-
|
62
51
|
end
|
63
|
-
|
64
52
|
end
|
65
|
-
|
66
53
|
end
|
67
|
-
|
68
54
|
end
|
@@ -1,24 +1,22 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CustomFields
|
3
4
|
module Types
|
4
|
-
|
5
5
|
module Boolean
|
6
|
-
|
7
6
|
module Field; end
|
8
7
|
|
9
8
|
module Target
|
10
|
-
|
11
9
|
extend ActiveSupport::Concern
|
12
10
|
|
13
11
|
module ClassMethods
|
14
|
-
|
15
12
|
# Adds a boolean field. It can not be required.
|
16
13
|
#
|
17
14
|
# @param [ Class ] klass The class to modify
|
18
15
|
# @param [ Hash ] rule It contains the name of the field.
|
19
16
|
#
|
20
17
|
def apply_boolean_custom_field(klass, rule)
|
21
|
-
klass.field rule['name'], type:
|
18
|
+
klass.field rule['name'], type: 'Boolean', localize: rule['localized'] || false,
|
19
|
+
default: rule['default'].nil? ? false : rule['default']
|
22
20
|
end
|
23
21
|
|
24
22
|
# Build a hash storing the boolean value (true / false) for
|
@@ -41,15 +39,10 @@ module CustomFields
|
|
41
39
|
# @param [ Hash ] attributes The attributes used to fetch the values
|
42
40
|
#
|
43
41
|
def boolean_attribute_set(instance, name, attributes)
|
44
|
-
|
42
|
+
default_attribute_set(instance, name, attributes)
|
45
43
|
end
|
46
|
-
|
47
44
|
end
|
48
|
-
|
49
45
|
end
|
50
|
-
|
51
46
|
end
|
52
|
-
|
53
47
|
end
|
54
|
-
|
55
48
|
end
|