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 +4 -4
- data/lib/slim_form_object/assign.rb +78 -110
- data/lib/slim_form_object/data_object.rb +73 -0
- data/lib/slim_form_object/form_helpers/extension_actionview.rb +27 -168
- data/lib/slim_form_object/helpers.rb +7 -7
- data/lib/slim_form_object/processing.rb +53 -27
- data/lib/slim_form_object/saver.rb +46 -30
- data/lib/slim_form_object/validator.rb +9 -20
- data/lib/slim_form_object/version.rb +1 -1
- data/lib/slim_form_object.rb +1 -0
- metadata +3 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f9ec59874945c8a7ee3c6abb9fb4fd58999d9fd5ade2e950957e4cdd5ceff95
|
4
|
+
data.tar.gz: d1b79735bb67d58cce0982f6e91be53599226c0b7d9835f52791f2c6140ef33f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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, :
|
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
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
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
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
45
|
-
|
46
|
-
|
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
|
52
|
-
|
53
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
71
|
-
|
72
|
-
|
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
|
77
|
-
|
78
|
-
|
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
|
83
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
|
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
|
-
|
91
|
-
include HelperMethods
|
58
|
+
if const_exists?('ActionView::Helpers')
|
92
59
|
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
110
|
-
class Base
|
64
|
+
class DateTimeSelector
|
111
65
|
include HelperMethods
|
112
66
|
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
187
|
-
|
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
|
-
|
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
|
-
|
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,
|
6
|
+
def get_class_of(snake_model_name, base_module=nil)
|
7
7
|
pref = base_module ? (base_module.to_s + '::') : ''
|
8
|
-
|
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
|
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, :
|
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
|
-
|
17
|
-
|
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
|
-
|
24
|
-
define_method(:
|
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
|
-
|
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
|
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
|
102
|
-
self.
|
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(:
|
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)
|
120
|
-
define_singleton_method(:before_save_form_block)
|
121
|
-
define_singleton_method(:after_save_form_block)
|
122
|
-
define_singleton_method(:before_validation_form_block)
|
123
|
-
define_singleton_method(: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, :
|
5
|
+
attr_reader :form_object, :params, :validator, :data_objects_arr
|
6
6
|
|
7
7
|
def initialize(form_object)
|
8
|
-
@form_object
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
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
|
-
|
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
|
-
|
26
|
+
_save
|
28
27
|
end
|
29
28
|
true
|
30
29
|
end
|
31
30
|
|
32
31
|
private
|
33
32
|
|
34
|
-
def
|
33
|
+
def _save
|
35
34
|
ActiveRecord::Base.transaction do
|
36
35
|
form_object.before_save_form_block.call(form_object)
|
37
|
-
|
38
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
61
|
-
|
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
|
-
|
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, :
|
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
|
-
@
|
12
|
-
@
|
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(
|
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(
|
36
|
-
|
37
|
-
set_errors( snake(
|
38
|
-
validation_objects(
|
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)
|
data/lib/slim_form_object.rb
CHANGED
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:
|
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-
|
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
|