slim_form_object 2.1.2 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25c66a76b49d989ba6a6c9062d350e75a2ead10bbf4e956c5ee4ae7eff1ce5e8
4
- data.tar.gz: 3716afd6b47bc40d0ceb0f132666e5a43ea927f80d07d2c93f0c1e958aafb1e5
3
+ metadata.gz: 5f9ec59874945c8a7ee3c6abb9fb4fd58999d9fd5ade2e950957e4cdd5ceff95
4
+ data.tar.gz: d1b79735bb67d58cce0982f6e91be53599226c0b7d9835f52791f2c6140ef33f
5
5
  SHA512:
6
- metadata.gz: d71453875860516f9fe15c1be2fd55fec2c1dd7621f25be306ab2593b60475732a6d796f69bd19e0318dcb535163fd54e68415e95d08722741bd0cc259f2c607
7
- data.tar.gz: d9874d69bef44a949ba1c11fe21956c8c1107384dce2175e5a270d4488111bed08a7c6c1fa23e21231b93623083ca95e40227c8fa03cfa963a8943723ad08e98
6
+ metadata.gz: f1889239d73747ed8812c5e10d20494cf876d434500b3576f8143035155e622cb33a6d8f39d8f12ae006e6289ae41feb2fd0006b40978ad5e2463db0f89ad705
7
+ data.tar.gz: dc5e445500ca32ef4b761d1721f9037fd258d682d0a51c6963d703615c430a08e5d2d4d46f6380a2b260ef2e3958f6e0f97f9e7cb6241009cbac5e53c6029e11
@@ -2,148 +2,116 @@ module SlimFormObject
2
2
  class Assign
3
3
  include ::HelperMethods
4
4
 
5
- attr_reader :form_object, :params, :data_for_save, :base_module, :validator
5
+ attr_reader :form_object, :params, :data_for_assign
6
+ attr_accessor :data_objects_arr
6
7
 
7
8
  def initialize(form_object)
8
- @form_object = form_object
9
- @base_module = form_object.class.base_module
10
- @params = form_object.params
11
- @validator = Validator.new(form_object)
12
- @data_for_save = []
9
+ @form_object = form_object
10
+ @params = form_object.params
11
+ @structure = form_object.data_structure
12
+ @data_for_assign = []
13
+ @data_objects_arr = []
13
14
  end
14
15
 
15
- def apply_parameters
16
- make_all_objects_with_attributes
17
- clear_nil_objects
16
+ def apply_parameters_and_make_objects
17
+ parse_params
18
+ @data_objects_arr = make_data_objects(data_for_assign)
19
+ associate_all_objects(data_objects_arr)
18
20
 
19
- data_for_save
20
- end
21
-
22
- def associate_objects
23
- associate_all_nested_objects(data_for_save)
24
- associate_all_main_objects(data_for_save)
25
-
26
- data_for_save
21
+ data_objects_arr
27
22
  end
28
23
 
29
24
  private
30
25
 
31
- def clear_nil_objects
32
- arr_ids_nil_object = []
33
- find_ids_nil_object(arr_ids_nil_object, data_for_save)
34
- delete_hash_nil_objects(arr_ids_nil_object, data_for_save)
35
- end
36
-
37
- def delete_hash_nil_objects(ids_arr, nested_array)
38
- nested_array.select!{|e| !ids_arr.include?(e.object_id)}
39
- nested_array.each do |hash|
40
- delete_hash_nil_objects(ids_arr, hash[:nested])
26
+ # data_for_assign format
27
+ #
28
+ # [
29
+ # { :model => Product(id: integer, category_id: integer, brand_id: integer),
30
+ # :attributes => {:id=>"3871", :category_id=>"1", :brand_id=>"1"},
31
+ # :nested => [
32
+ # { :model => FiltersProduct(id: integer, product_id: integer, filter_id: integer, value_id: integer),
33
+ # :attributes => {:id=>"", :product_id=>"111", filter_id: "222", value_id: "333"},
34
+ # :nested => []
35
+ # }
36
+ # ]
37
+ # }
38
+ # ]
39
+ def make_hash_objects_and_nested_objects(key_params, value_params)
40
+ model = get_class_of(key_params)
41
+ attributes = {}
42
+ nested = []
43
+
44
+ value_params.each do |key, value|
45
+ if is_nested?(value)
46
+ if value.is_a?(Array)
47
+ value.each { |hash_params| nested << make_hash_objects_and_nested_objects(key, hash_params) }
48
+ elsif value.is_a?(ActionController::Parameters)
49
+ value.each { |index, hash_params| nested << make_hash_objects_and_nested_objects(key, hash_params) }
50
+ else
51
+ nested << make_hash_objects_and_nested_objects(key, value)
52
+ end
53
+ else
54
+ element = {key.to_sym => value}
55
+ attributes.merge!(element)
56
+ end
41
57
  end
58
+
59
+ {model: model, attributes: attributes, nested: nested}
42
60
  end
43
61
 
44
- def find_ids_nil_object(ids_arr, nested_array)
45
- nested_array.each do |hash|
46
- ids_arr << hash.object_id if !validator.save_if_object_is_empty?(hash[:essence][:object])
47
- find_ids_nil_object(ids_arr, hash[:nested])
62
+ def parse_params
63
+ params.each do |main_model_name, attributes|
64
+ data_for_assign << make_hash_objects_and_nested_objects(main_model_name, attributes)
48
65
  end
49
66
  end
50
67
 
51
- def associate_all_nested_objects(nested_array, object=nil)
52
- nested_array.each do |hash|
53
- to_bind_models(object, hash[:essence][:object]) if object and validator.allow_to_associate_objects?(object, hash[:essence][:object])
54
- associate_all_nested_objects(hash[:nested], hash[:essence][:object])
68
+ def is_nested?(value)
69
+ def nested?(e)
70
+ e.class == ActionController::Parameters or e.class == Hash
55
71
  end
56
- end
57
72
 
58
- def associate_all_main_objects(data_for_save)
59
- objects = Array.new(data_for_save)
60
- while object = objects.delete( objects[0] )
61
- object_1 = object[:essence][:object]
62
- objects.each do |hash|
63
- object_2 = hash[:essence][:object]
64
- next if !object_1.new_record? and !object_2.new_record?
65
- to_bind_models(object_1, object_2)
66
- end
73
+ return true if nested?(value)
74
+
75
+ if value.class == Array
76
+ value.select{ |e| nested?(e) }.size == value.size
67
77
  end
68
78
  end
69
79
 
70
- def make_all_objects_with_attributes
71
- params.each do |main_model_name, hash|
72
- assign_objects_attributes(main_model_name, hash, data_for_save, :main)
80
+ def make_data_objects(data_for_assign)
81
+ data_for_assign.map do |data|
82
+ data_object = DataObject.new(name: snake(data[:model]), attributes: data[:attributes], form_object: form_object)
83
+ data_object.nested = make_data_objects(data[:nested])
84
+ data_object
73
85
  end
74
86
  end
75
87
 
76
- def nested(model_name, nested_array, result_array)
77
- nested_array.each do |nested_object|
78
- assign_objects_attributes(model_name, nested_object, result_array, :nested)
88
+ def associate_objects(data_objects)
89
+ objects = Array.new(data_objects)
90
+ while data_object_1 = objects.delete( objects[0] )
91
+ associate_all_objects(data_object_1.nested)
92
+ objects.each do |data_object_2|
93
+ data_object_1.associate_with(data_object_2.associated_object)
94
+ end
79
95
  end
80
96
  end
81
97
 
82
- def is_nested?(value)
83
- return false unless value.class == Array
84
- value.select{ |e| e.class == ActionController::Parameters or e.class == Hash }.size == value.size
85
- end
98
+ def associate_all_objects(objects)
99
+ associate_objects(objects)
86
100
 
87
- def assign_objects_attributes(model_name, hash, result_array, type)
88
- object_hash = {}
89
- object = type == :main ? form_object.send(model_name.to_sym) : get_class_of(model_name, base_module).new
90
- object_hash[:nested] = []
91
- object_attrs = {}
92
- hash.each do |key, val|
93
- if is_nested?(val)
94
- nested(key, val, object_hash[:nested])
95
- else
96
- object_attrs.merge!({"#{key}": val})
101
+ objects.each do |data_object|
102
+ data_object.nested.each do |nested_data_object|
103
+ data_object.associate_with(nested_data_object.associated_object)
97
104
  end
98
105
  end
99
- object.assign_attributes(object_attrs)
100
- object_hash[:essence] = {model: model_name, object: object}
101
- result_array << object_hash
102
106
  end
103
107
 
104
- # PARAMS FORMAT
105
- # {
106
- # "user"=> {
107
- # "email"=>"kjbkj@bk.ddd",
108
- # "password"=>"dsmndvvs",
109
- # "password_confirmation"=>"jvdjshvd",
110
- # "address_user"=> [
111
- # {
112
- # "first_name"=>"dsdsd",
113
- # "last_name"=>"kjhkjbk",
114
- # "order"=> [
115
- # {
116
- # "created_at"=>"kjkjb",
117
- # "updated_at"=>"kjbkjb"
118
- # }
119
- # ]
120
- # }
121
- # ]
122
- # }
123
- # }
108
+ def clean_data_objects_arr(objects)
109
+ objects.select! do |data_object|
110
+ clean_data_objects_arr(data_object.nested)
111
+ data_object.save_if_nil_or_empty?
112
+ end
113
+ end
124
114
 
125
- # make_all_objects_with_attributes() EXAMPLE @data_for_save FORMAT
126
- #
127
- # [
128
- # {
129
- # essence: {model: 'user', object: WoodShop::User.new(attributes)},
130
- # nested: [
131
- # {
132
- # essence: {model: 'address_user', object: WoodShop::AddressUser.new(attributes)},
133
- # nested: [
134
- # {
135
- # essence: {model: 'image', object: WoodShop::Image.new(attributes)},
136
- # nested: []
137
- # },
138
- # {
139
- # essence: {model: 'image', object: WoodShop::Image.new(attributes)},
140
- # nested: []
141
- # }
142
- # ]
143
- # }
144
- # ]
145
- # }
146
- # ]
147
115
  end
148
116
  end
149
117
 
@@ -0,0 +1,73 @@
1
+ module SlimFormObject
2
+ class DataObject
3
+ include ::HelperMethods
4
+
5
+ attr_reader :name, :model, :attributes, :object, :associated_object, :form_object
6
+ attr_accessor :nested
7
+
8
+ def initialize(name: nil, attributes: {}, form_object: nil)
9
+ @name = name
10
+ @model = get_class_of(name)
11
+ @attributes = attributes
12
+ @form_object = form_object
13
+ @object = make_object
14
+ @associated_object = assign_attributes_for(make_object)
15
+ assign_attributes!
16
+ end
17
+
18
+ def associate_with(other_object, stage: nil)
19
+ case stage
20
+ when 1
21
+ obj = object
22
+ when 2
23
+ obj = object
24
+ else
25
+ obj = associated_object
26
+ end
27
+
28
+ return obj if (stage != 2 and !obj.new_record? and !other_object.new_record?)
29
+
30
+ to_bind_models(obj, other_object)
31
+ end
32
+
33
+ def save_if_nil_or_empty?
34
+ save_if_empty? and save_if_nil?
35
+ end
36
+
37
+ def save_if_empty?
38
+ !form_object.not_save_if_empty_arr.include?(model) or !empty_attributes?
39
+ end
40
+
41
+ def save_if_nil?
42
+ !form_object.not_save_if_nil_arr.include?(model) or !nil_attributes?
43
+ end
44
+
45
+ private
46
+
47
+ def empty_attributes?
48
+ return false if nil_attributes?
49
+ attributes.each { |key, value| return false if value&.to_s&.strip != '' }
50
+ true
51
+ end
52
+
53
+ def nil_attributes?
54
+ attributes.empty?
55
+ end
56
+
57
+ def assign_attributes!
58
+ assign_attributes_for(object)
59
+ end
60
+
61
+ def assign_attributes_for(obj)
62
+ obj.assign_attributes(attributes)
63
+ obj
64
+ end
65
+
66
+ def make_object
67
+ attributes[:id].to_i > 0 ? model.find(attributes[:id]) : model.new
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+
@@ -1,3 +1,9 @@
1
+ def const_exists?(const_name)
2
+ return true if Module.const_get(const_name)
3
+ rescue NameError
4
+ return false
5
+ end
6
+
1
7
  module HelperMethods
2
8
 
3
9
  private
@@ -14,51 +20,16 @@ module HelperMethods
14
20
  /^([^-]+)-([^-]+)(\([\s\S]+\))$/
15
21
  end
16
22
 
17
- def sfo_collection_ads_regexp
18
- /_ids$/
19
- end
20
-
21
- def sfo_form_attribute?(object)
22
- object.class.ancestors[1] == SlimFormObject::Base if object
23
- end
24
-
25
- def sfo_attr?(method)
26
- sfo_single_attr?(method)
27
- end
28
-
29
- def sfo_single_attr?(method)
30
- method.to_s[sfo_single_attr_regexp] ? true : false
31
- end
32
-
33
23
  def sfo_date_attr?(tag_name)
34
24
  tag_name.to_s[sfo_date_attr_regexp] ? true : false
35
25
  end
36
26
 
37
- def sfo_collection_ads_attr?(tag_name)
38
- tag_name.to_s[sfo_collection_ads_regexp] ? true : false
39
- end
40
-
41
- def sfo_get_tag_name(object_name, method, multiple, options)
42
- model_name, attr_name = apply_expression_text(method)
43
- if options[:sfo_nested]
44
- "#{object_name}[#{model_name}][][#{attr_name}]#{"[]" if multiple}"
45
- else
46
- "#{object_name}[#{model_name}][#{attr_name}]#{"[]" if multiple}"
47
- end
48
- end
49
-
50
- def sfo_get_method_name(method)
51
- if sfo_single_attr?(method) and !sfo_collection_ads_attr?(method)
52
- model_name, attr_name = apply_expression_text(method)
53
- method = "#{model_name}_#{attr_name}"
54
- end
55
-
56
- method
57
- end
58
-
59
27
  def sfo_get_date_tag_name(prefix, tag_name, options)
60
- model_name, attr_name, date_type = apply_expression_date(tag_name)
61
- if options[:sfo_nested]
28
+ # model_name, attr_name, date_type = apply_expression_date(tag_name)
29
+ attr_name, date_type = apply_expression_text(tag_name)
30
+ model_name = options[:sfo_model]
31
+
32
+ if options[:sfo_model]
62
33
  "#{prefix}[#{model_name}][][#{attr_name}#{date_type}]"
63
34
  else
64
35
  "#{prefix}[#{model_name}][#{attr_name}#{date_type}]"
@@ -83,145 +54,33 @@ module HelperMethods
83
54
  end
84
55
  end
85
56
 
86
- module ActionView
87
- module Helpers
88
- # EXTENSIONS
89
57
 
90
- class DateTimeSelector
91
- include HelperMethods
58
+ if const_exists?('ActionView::Helpers')
92
59
 
93
- def input_name_from_type(type)
94
- prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
95
- prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
96
-
97
- field_name = @options[:field_name] || type
98
- if @options[:include_position]
99
- field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
100
- end
101
- options = self.instance_variable_get(:@options)
102
- return sfo_get_date_tag_name(prefix, field_name, options) if sfo_date_attr?(field_name)
103
-
104
- @options[:discard_type] ? prefix : "#{prefix}[#{field_name}]"
105
-
106
- end
107
- end
60
+ module ActionView
61
+ module Helpers
62
+ # EXTENSIONS
108
63
 
109
- module Tags
110
- class Base
64
+ class DateTimeSelector
111
65
  include HelperMethods
112
66
 
113
- private
114
-
115
- # TODO: Find a better way to solve this issue!
116
- # This patch is needed since this Rails commit:
117
- # https://github.com/rails/rails/commit/c1a118a
118
- if defined? ::ActiveRecord
119
- if ::ActiveRecord::VERSION::STRING < '5.2'
120
- def value(object)
121
- method_name = @options[:sfo_nested] ? apply_expression_text(@method_name)[1] : sfo_get_method_name(@method_name)
122
- object.send method_name if object # use send instead of public_send
123
- end
124
- else # rails/rails#29791
125
- def value
126
- method_name = @options[:sfo_nested] ? apply_expression_text(@method_name)[1] : sfo_get_method_name(@method_name)
127
- if @allow_method_names_outside_object
128
- object.send method_name if object && object.respond_to?(@method_name, true)
129
- else
130
- object.send method_name if object
131
- end
132
- end
133
- end
134
- end
135
-
136
- def tag_name(multiple = false, index = nil)
137
- options = self.instance_variable_get(:@options)
138
- return sfo_get_tag_name(@object_name, sanitized_method_name, multiple, options) if sfo_attr?(sanitized_method_name)
139
-
140
- if index
141
- "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
142
- else
143
- "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
144
- end
145
- end
146
- end
147
- end
148
-
149
- class FormBuilder
150
- include HelperMethods
151
-
152
- def initialize(object_name, object, template, options)
153
- @nested_child_index = {}
154
- @object_name, @object, @template, @options = object_name, object, template, options
155
- @default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {}
156
- @default_options.merge!( {sfo_nested: options[:sfo_nested], sfo_main: options[:sfo_main]} )
157
- if ::ActionView::VERSION::STRING > '5.2'
158
- @default_html_options = @default_options.except(:skip_default_ids, :allow_method_names_outside_object)
159
- end
160
- convert_to_legacy_options(@options)
161
-
162
- if @object_name.to_s.match(/\[\]$/)
163
- if (object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param)
164
- @auto_index = object.to_param
165
- else
166
- raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
167
- end
168
- end
169
-
170
- @multipart = nil
171
- @index = options[:index] || options[:child_index]
172
- end
67
+ def input_name_from_type(type)
68
+ prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
69
+ prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
173
70
 
174
- def fields_for(record_name, record_object = nil, fields_options = {}, &block)
175
- fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
176
- fields_options[:builder] ||= options[:builder]
177
- fields_options[:namespace] = options[:namespace]
178
- fields_options[:parent_builder] = self
179
- self.options[:sfo_nested] ? fields_options.merge!({sfo_main: false}) : fields_options.merge!({sfo_main: true})
180
-
181
- case record_name
182
- when String, Symbol
183
- if nested_attributes_association?(record_name)
184
- return fields_for_with_nested_attributes(record_name, record_object, fields_options, block)
71
+ field_name = @options[:field_name] || type
72
+ if @options[:include_position]
73
+ field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
185
74
  end
186
- else
187
- record_object = record_name.is_a?(Array) ? record_name.last : record_name
188
- record_name = model_name_from_record_or_class(record_object).param_key
189
- end
190
-
191
- object_name = @object_name
192
- index = if options.has_key?(:index)
193
- options[:index]
194
- elsif defined?(@auto_index)
195
- object_name = object_name.to_s.sub(/\[\]$/, "")
196
- @auto_index
197
- end
75
+ options = self.instance_variable_get(:@options)
76
+ return sfo_get_date_tag_name(prefix, field_name, options) if sfo_date_attr?(field_name)
198
77
 
199
- record_name = if index
200
- "#{object_name}[#{index}][#{record_name}]"
201
- elsif record_name.to_s.end_with?("[]")
202
- record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]")
203
- "#{object_name}#{record_name}"
204
- else
205
- "#{object_name}[#{record_name}]"
206
- end
207
- fields_options[:child_index] = index
78
+ @options[:discard_type] ? prefix : "#{prefix}[#{field_name}]"
208
79
 
209
- if fields_options[:sfo_nested]
210
- record_object = object if !record_object
211
- record_name = record_name + '[][]' unless fields_options[:sfo_main]
212
80
  end
213
- @template.fields_for(record_name, record_object, fields_options, &block)
214
81
  end
215
- end
216
82
 
217
- module FormHelper
218
- include HelperMethods
219
-
220
- # def fields_for(record_name, record_object = nil, options = {}, &block)
221
- # builder = instantiate_builder(record_name, record_object, options)
222
- # capture(builder, &block)
223
- # end
83
+
224
84
  end
225
-
226
85
  end
227
- end
86
+ end
@@ -3,21 +3,21 @@ module HelperMethods
3
3
  method( snake(model.to_s).to_sym ).call
4
4
  end
5
5
 
6
- def get_class_of(snake_model_name, base_modulenil)
6
+ def get_class_of(snake_model_name, base_module=nil)
7
7
  pref = base_module ? (base_module.to_s + '::') : ''
8
- Object.const_get( pref + snake_model_name.to_s.split('_').map(&:capitalize).join )
8
+ Module.const_get( pref + snake_model_name.to_s.split('_').map(&:capitalize).join )
9
9
  rescue
10
10
  nil
11
11
  end
12
12
 
13
13
  def to_bind_models(object_1, object_2)
14
- if object_2.new_record?
15
- assignment_to_each_other(object_2, object_1)
16
- else
14
+ if object_1.new_record?
17
15
  assignment_to_each_other(object_1, object_2)
16
+ object_1
17
+ else
18
+ assignment_to_each_other(object_2, object_1)
19
+ object_2
18
20
  end
19
-
20
- object_1
21
21
  end
22
22
 
23
23
  def assignment_to_each_other(object_1, object_2)
@@ -4,7 +4,7 @@ module SlimFormObject
4
4
  include ::HelperMethods
5
5
  extend ::HelperMethods
6
6
 
7
- attr_accessor :params, :data_for_save
7
+ attr_accessor :params, :data_objects_arr
8
8
 
9
9
  class << self
10
10
  attr_accessor :base_module
@@ -13,20 +13,50 @@ module SlimFormObject
13
13
  define_method(:model_name) { ActiveModel::Name.new(self, nil, name) }
14
14
  end
15
15
 
16
- def init_single_models(*args)
17
- define_array_of_models(:array_of_all_models, args)
16
+ # data_structure
17
+ def input_data_structure(**structure)
18
+ instance_eval do
19
+ define_method(:data_structure) { structure }
20
+ end
21
+
22
+ define_array_of_models(:array_of_all_models, get_main_models_from_structure(structure))
18
23
  end
19
- alias_method :init_models, :init_single_models
20
24
 
25
+ # array_models_which_not_save_if_empty
21
26
  def not_save_empty_object_for(*args)
22
27
  args.each { |model| raise "#{model.to_s} - type is not a Class" if model.class != Class }
23
- self.instance_eval do
24
- define_method(:array_models_which_not_save_if_empty) { args }
28
+ instance_eval do
29
+ define_method(:not_save_if_empty_arr) { args }
30
+ end
31
+ end
32
+
33
+ def not_save_nil_object_for(*args)
34
+ args.each { |model| raise "#{model.to_s} - type is not a Class" if model.class != Class }
35
+ instance_eval do
36
+ define_method(:not_save_if_nil_arr) { args }
37
+ end
38
+ end
39
+
40
+ # CALLBACKS
41
+ %w(allow_to_save_object allow_to_associate_objects before_save_form after_save_form before_validation_form after_validation_form).each do |method_name|
42
+ define_method("#{method_name}".to_sym) do |&block|
43
+ instance_eval do
44
+ define_method("#{method_name}_block".to_sym) { block }
45
+ end if block
46
+ end
47
+ end
48
+ # END CALLBACKS
49
+
50
+ private
51
+
52
+ def get_main_models_from_structure(structure)
53
+ structure.keys.map do |main_model_name|
54
+ get_class_of(main_model_name)
25
55
  end
26
56
  end
27
57
 
28
58
  def define_array_of_models(name, args)
29
- self.instance_eval do
59
+ instance_eval do
30
60
  define_method(name) { args }
31
61
  end
32
62
  make_methods_for_objects_of(args)
@@ -45,22 +75,12 @@ module SlimFormObject
45
75
  end
46
76
  end
47
77
  end
48
-
49
- # CALLBACKS
50
- %w(allow_to_save_object allow_to_associate_objects before_save_form after_save_form before_validation_form after_validation_form).each do |method_name|
51
- define_method("#{method_name}".to_sym) do |&block|
52
- self.instance_eval do
53
- define_method("#{method_name}_block".to_sym) { block }
54
- end if block
55
- end
56
- end
57
- # END CALLBACKS
58
78
  end
59
79
 
60
80
  def method_missing(name, *args, &block)
61
81
  if name[/_ids$/]
62
82
  model_name, attr_name = get_model_and_method_names(name)
63
- return self.send(model_name.to_sym).send(attr_name.to_sym)
83
+ return send(model_name.to_sym).send(attr_name.to_sym)
64
84
  end
65
85
  super(name, args, block)
66
86
  end
@@ -91,6 +111,11 @@ module SlimFormObject
91
111
  Validator.new(self).validate_form_object
92
112
  end
93
113
 
114
+ def permit_params(params)
115
+ return {} if params.empty?
116
+ params.require(snake(model_name.name).gsub(/_+/, '_')).permit(data_structure)
117
+ end
118
+
94
119
  private
95
120
 
96
121
  def require_extensions
@@ -98,9 +123,8 @@ module SlimFormObject
98
123
  end
99
124
 
100
125
  def apply
101
- assign = Assign.new(self)
102
- self.data_for_save = assign.apply_parameters
103
- self.data_for_save = assign.associate_objects
126
+ assign = Assign.new(self)
127
+ self.data_objects_arr = assign.apply_parameters_and_make_objects
104
128
  end
105
129
 
106
130
  def get_or_add_default_objects
@@ -114,14 +138,16 @@ module SlimFormObject
114
138
  end
115
139
 
116
140
  def default_settings
117
- define_singleton_method(:array_models_which_not_save_if_empty) { [] } unless respond_to?(:array_models_which_not_save_if_empty)
141
+ define_singleton_method(:not_save_if_empty_arr) { [] } unless respond_to?(:not_save_if_empty_arr)
142
+ define_singleton_method(:not_save_if_nil_arr) { [] } unless respond_to?(:not_save_if_nil_arr)
118
143
  define_singleton_method(:allow_to_associate_objects_block) { Proc.new { true } } unless respond_to?(:allow_to_associate_objects_block)
119
- define_singleton_method(:allow_to_save_object_block) { Proc.new { true } } unless respond_to?(:allow_to_save_object_block)
120
- define_singleton_method(:before_save_form_block) { Proc.new {} } unless respond_to?(:before_save_form_block)
121
- define_singleton_method(:after_save_form_block) { Proc.new {} } unless respond_to?(:after_save_form_block)
122
- define_singleton_method(:before_validation_form_block) { Proc.new {} } unless respond_to?(:before_validation_form_block)
123
- define_singleton_method(:after_validation_form_block) { Proc.new {} } unless respond_to?(:after_validation_form_block)
144
+ define_singleton_method(:allow_to_save_object_block) { Proc.new { true } } unless respond_to?(:allow_to_save_object_block)
145
+ define_singleton_method(:before_save_form_block) { Proc.new {} } unless respond_to?(:before_save_form_block)
146
+ define_singleton_method(:after_save_form_block) { Proc.new {} } unless respond_to?(:after_save_form_block)
147
+ define_singleton_method(:before_validation_form_block) { Proc.new {} } unless respond_to?(:before_validation_form_block)
148
+ define_singleton_method(:after_validation_form_block) { Proc.new {} } unless respond_to?(:after_validation_form_block)
124
149
  end
150
+
125
151
  end
126
152
  end
127
153
 
@@ -2,19 +2,18 @@ module SlimFormObject
2
2
  class Saver
3
3
  include ::HelperMethods
4
4
 
5
- attr_reader :form_object, :params, :validator, :base_module, :data_for_save
5
+ attr_reader :form_object, :params, :validator, :data_objects_arr
6
6
 
7
7
  def initialize(form_object)
8
- @form_object = form_object
9
- @base_module = form_object.class.base_module
10
- @params = form_object.params
11
- @data_for_save = form_object.data_for_save
12
- @validator = Validator.new(form_object)
8
+ @form_object = form_object
9
+ @params = form_object.params
10
+ @data_objects_arr = form_object.data_objects_arr
11
+ @validator = Validator.new(form_object)
13
12
  end
14
13
 
15
14
  def save
16
15
  if form_object.valid?
17
- save_all
16
+ _save
18
17
  return true
19
18
  end
20
19
  false
@@ -24,52 +23,69 @@ module SlimFormObject
24
23
 
25
24
  def save!
26
25
  if form_object.valid?
27
- save_all
26
+ _save
28
27
  end
29
28
  true
30
29
  end
31
30
 
32
31
  private
33
32
 
34
- def save_all
33
+ def _save
35
34
  ActiveRecord::Base.transaction do
36
35
  form_object.before_save_form_block.call(form_object)
37
- save_main_objects
38
- save_nested_objects
36
+ stage_1(data_objects_arr)
37
+ stage_2(data_objects_arr)
38
+ stage_3(data_objects_arr)
39
39
  form_object.after_save_form_block.call(form_object)
40
40
  end
41
41
  end
42
42
 
43
- def save_main_objects
44
- objects = Array.new(data_for_save)
45
- while object = objects.delete( objects[0] )
46
- object_1 = object[:essence][:object]
47
- objects.each{ |hash| save_objects(object_1, hash[:essence][:object]) }
48
- save_last_model_if_not_associations(object_1)
43
+ # association per parent with all nested objects
44
+ def stage_1(objects)
45
+ objects.each do |data_object|
46
+ data_object.nested.each do |nested_data_object|
47
+ data_object.associate_with(nested_data_object.object, stage: 1)
48
+ end
49
+ stage_1(data_object.nested)
50
+ end
51
+ end
52
+
53
+ # save all objects
54
+ def stage_2(objects)
55
+ objects.each do |data_object|
56
+ stage_2(data_object.nested)
57
+ save_object(data_object.object)
58
+ end
59
+ end
60
+
61
+ # associate and save between a nested objects
62
+ def stage_3(objects)
63
+ associate_and_save_objects(objects)
64
+
65
+ objects.each do |data_object|
66
+ stage_3(data_object.nested)
49
67
  end
50
68
  end
51
69
 
52
- def save_nested_objects
53
- data_for_save.each do |main_object|
54
- main_object[:nested].each do |object|
55
- save_object(object[:essence][:object])
70
+ def associate_and_save_objects(data_objects)
71
+ objects = Array.new(data_objects)
72
+ while data_object_1 = objects.delete( objects[0] )
73
+ objects.each do |data_object_2|
74
+ obj = data_object_1.associate_with(data_object_2.object, stage: 2)
75
+ save_object(obj)
56
76
  end
57
77
  end
58
78
  end
59
79
 
60
- def save_objects(object_1, object_2)
61
- object_for_save = to_bind_models(object_1, object_2)
62
- save_object(object_for_save)
80
+ def allow_to_save(object_of_model)
81
+ object_of_model.valid? and object_of_model.changed? and validator.allow_to_save_object?(object_of_model)
63
82
  end
64
83
 
65
84
  def save_object(object_of_model)
66
- object_of_model.save! if validator.allow_to_save_object?(object_of_model)
85
+ if allow_to_save(object_of_model)
86
+ object_of_model.save!
87
+ end
67
88
  end
68
89
 
69
- def save_last_model_if_not_associations(object_1)
70
- association_trigger = false
71
- data_for_save.each { |hash| association_trigger = true if get_reflection(object_1.class, hash[:essence][:object].class) }
72
- save_object(object_1) unless association_trigger
73
- end
74
90
  end
75
91
  end
@@ -2,26 +2,22 @@ module SlimFormObject
2
2
  class Validator
3
3
  include ::HelperMethods
4
4
 
5
- attr_reader :form_object, :params, :array_models_which_not_save_if_empty, :base_module, :data_for_save
5
+ attr_reader :form_object, :params, :not_save_if_empty_arr, :not_save_if_nil_arr, :data_objects_arr
6
6
 
7
7
  def initialize(form_object)
8
8
  @form_object = form_object
9
- @base_module = form_object.class.base_module
10
9
  @params = form_object.params
11
- @data_for_save = form_object.data_for_save
12
- @array_models_which_not_save_if_empty = form_object.array_models_which_not_save_if_empty
10
+ @data_objects_arr = form_object.data_objects_arr
11
+ @not_save_if_empty_arr = form_object.not_save_if_empty_arr
12
+ @not_save_if_nil_arr = form_object.not_save_if_nil_arr
13
13
  end
14
14
 
15
15
  def validate_form_object
16
16
  form_object.before_validation_form_block.call(form_object)
17
- validation_objects(data_for_save)
17
+ validation_objects(data_objects_arr)
18
18
  form_object.after_validation_form_block.call(form_object)
19
19
  end
20
20
 
21
- def save_if_object_is_empty?(object)
22
- !(all_attributes_is_nil?(object) and array_models_which_not_save_if_empty.include?(object.class))
23
- end
24
-
25
21
  def allow_to_save_object?(object)
26
22
  form_object.allow_to_save_object_block.call(object)
27
23
  end
@@ -32,18 +28,11 @@ module SlimFormObject
32
28
 
33
29
  private
34
30
 
35
- def validation_objects(nested_array)
36
- nested_array.each do |hash|
37
- set_errors( snake(hash[:essence][:object].class), hash[:essence][:object].errors ) unless hash[:essence][:object].valid?
38
- validation_objects(hash[:nested])
39
- end
40
- end
41
-
42
- def all_attributes_is_nil?(object)
43
- object.class.column_names.each do |attr_name|
44
- return false if object.send(attr_name.to_sym) != nil
31
+ def validation_objects(objects)
32
+ objects.each do |data_object|
33
+ set_errors( snake(data_object.model), data_object.associated_object.errors ) unless data_object.associated_object.valid?
34
+ validation_objects(data_object.nested)
45
35
  end
46
- true
47
36
  end
48
37
 
49
38
  def set_errors(object_name, object_errors)
@@ -1,3 +1,3 @@
1
1
  module SlimFormObject
2
- VERSION = "2.1.2"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -4,6 +4,7 @@ require "slim_form_object/validator"
4
4
  require "slim_form_object/processing"
5
5
  require "slim_form_object/assign"
6
6
  require "slim_form_object/saver"
7
+ require "slim_form_object/data_object"
7
8
 
8
9
  module SlimFormObject
9
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slim_form_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - woodcrust
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-08 00:00:00.000000000 Z
11
+ date: 2019-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.0.0
27
- - !ruby/object:Gem::Dependency
28
- name: actionview
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 4.0.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 4.0.0
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: bundler
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -162,6 +148,7 @@ files:
162
148
  - bin/slim_form_object
163
149
  - lib/slim_form_object.rb
164
150
  - lib/slim_form_object/assign.rb
151
+ - lib/slim_form_object/data_object.rb
165
152
  - lib/slim_form_object/form_helpers/extension_actionview.rb
166
153
  - lib/slim_form_object/helpers.rb
167
154
  - lib/slim_form_object/processing.rb