slim_form_object 0.5.23 → 1.0.1
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.rb +4 -1
- data/lib/slim_form_object/assign.rb +89 -0
- data/lib/slim_form_object/form_helpers/extension_actionview.rb +161 -0
- data/lib/slim_form_object/helpers.rb +9 -0
- data/lib/slim_form_object/processing.rb +81 -127
- data/lib/slim_form_object/saver.rb +81 -0
- data/lib/slim_form_object/tmp.rb +297 -0
- data/lib/slim_form_object/validator.rb +55 -0
- data/lib/slim_form_object/version.rb +1 -1
- data/spec/db/migrate/001_create_model_one.rb +1 -1
- data/spec/db/migrate/002_create_model_two.rb +1 -1
- data/spec/db/migrate/003_create_model_three.rb +1 -1
- data/spec/db/migrate/004_create_model_four.rb +1 -1
- data/spec/db/migrate/005_create_model_one_four.rb +1 -1
- data/spec/db/migrate/006_create_model_two_three.rb +1 -1
- metadata +23 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eead85525874b4ad6ac4fea0f9bdace9f2cc5f90
|
4
|
+
data.tar.gz: e382a9c9eabfcdf5744647916a6f9d68dc1e06bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65fc388efca69511b521c7c4589fdf0828f3f8ef5a6e4f4693b8bb78fc53370752e1563f1ef2692066c38b34b15d5cce7bc184d28fb7b1c4fbd9a5c356908346
|
7
|
+
data.tar.gz: c97e749fe60e6cf20a813aa9ff77ff24f68352122d863592c71d4a1cc96b06eb6eeb4146aa92353e9a7b8bb7801a7d66d50cbb4e9a8498ef7c2a8a96d9ec0203
|
data/lib/slim_form_object.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require "slim_form_object/version"
|
2
|
+
require "slim_form_object/form_helpers/extension_actionview"
|
2
3
|
require "slim_form_object/helpers"
|
4
|
+
require "slim_form_object/validator"
|
3
5
|
require "slim_form_object/processing"
|
6
|
+
require "slim_form_object/assign"
|
7
|
+
require "slim_form_object/saver"
|
4
8
|
|
5
9
|
module SlimFormObject
|
6
|
-
|
7
10
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module SlimFormObject
|
2
|
+
class Assign
|
3
|
+
include ::HelperMethods
|
4
|
+
|
5
|
+
attr_reader :form_object, :params, :array_all_objects_for_save, :not_save_this_model, :result_hash_updated_objects
|
6
|
+
|
7
|
+
def initialize(form_object)
|
8
|
+
@form_object = form_object
|
9
|
+
@params = form_object.params
|
10
|
+
@array_all_objects_for_save = form_object.array_all_objects_for_save
|
11
|
+
@not_save_this_model = form_object.not_save_this_model
|
12
|
+
@result_hash_updated_objects = {objects: [], nested_objects: {}}
|
13
|
+
end
|
14
|
+
|
15
|
+
def apply_parameters
|
16
|
+
filter_not_save_objects
|
17
|
+
update_objects_attributes
|
18
|
+
make_nested_objects
|
19
|
+
|
20
|
+
result_hash_updated_objects
|
21
|
+
end
|
22
|
+
|
23
|
+
def filter_not_save_objects
|
24
|
+
array_all_objects_for_save.reject do |object|
|
25
|
+
not_save_this_model.include?(object.class)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# STANDART OBJECTS
|
30
|
+
|
31
|
+
def update_objects_attributes
|
32
|
+
array_all_objects_for_save.each do |object|
|
33
|
+
object.assign_attributes(hash_params_of_object(object))
|
34
|
+
end
|
35
|
+
|
36
|
+
result_hash_updated_objects[:objects] = array_all_objects_for_save
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def hash_params_of_object(object)
|
41
|
+
if force_permit(params[snake(object.class.to_s)])
|
42
|
+
params[snake(object.class.to_s)]
|
43
|
+
else
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def force_permit(params)
|
49
|
+
return nil if params.class != ActionController::Parameters
|
50
|
+
params.instance_variable_set(:@permitted, true)
|
51
|
+
params
|
52
|
+
end
|
53
|
+
|
54
|
+
# NESTED OBJECTS
|
55
|
+
# example params
|
56
|
+
#
|
57
|
+
# "sfo-multiple"=>{
|
58
|
+
# snake_model_name "category_vacancy"=>{
|
59
|
+
# snake_object_name "specialty_vacancy"=>[
|
60
|
+
# parameters {"name"=>"4", "category_vacancy_id"=>"12"}, {"name"=>"6", "category_vacancy_id"=>"14"} ]}}
|
61
|
+
#
|
62
|
+
def make_nested_objects
|
63
|
+
params.keys.each do |key|
|
64
|
+
if key == 'sfo-multiple'
|
65
|
+
params[key].keys.each do |snake_model_name|
|
66
|
+
result_hash_updated_objects[:nested_objects][snake_model_name.to_sym] ||= []
|
67
|
+
|
68
|
+
params[key][snake_model_name].keys.each do |snake_object_name|
|
69
|
+
params[key][snake_model_name][snake_object_name].each do |parameters|
|
70
|
+
object = get_class_of_snake_model_name(snake_object_name).new
|
71
|
+
object.assign_attributes(force_permit(parameters))
|
72
|
+
result_hash_updated_objects[:nested_objects][snake_model_name.to_sym] << object
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module HelperMethods
|
4
|
+
def sfo_fields_for(name, object = nil, form_options: {}, options: {}, &block)
|
5
|
+
object = get_class_of_snake_model_name(name.to_s).new unless object
|
6
|
+
|
7
|
+
if options[:sfo_form]
|
8
|
+
form_object_class = get_class_of_snake_model_name(name.to_s)
|
9
|
+
name = "slim_form_object_#{name}"
|
10
|
+
object = form_object_class.new(form_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
fields_for(name, object, options, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def get_class_of_snake_model_name(snake_model_name)
|
19
|
+
Object.const_get( snake_model_name.split('_').map(&:capitalize).join )
|
20
|
+
end
|
21
|
+
|
22
|
+
def sfo_single_attr_regexp
|
23
|
+
/^([^-]+)-([^-]+)$/
|
24
|
+
end
|
25
|
+
|
26
|
+
def sfo_multiple_attr_regexp
|
27
|
+
/sfo-multiple/
|
28
|
+
end
|
29
|
+
|
30
|
+
def sfo_date_attr_regexp
|
31
|
+
/^([^-]+)-([^-]+)(\([\s\S]+\))$/
|
32
|
+
end
|
33
|
+
|
34
|
+
def sfo_form_attribute?(object)
|
35
|
+
object.class.ancestors[1] == SlimFormObject::Base if object
|
36
|
+
end
|
37
|
+
|
38
|
+
def sfo_attr?(method)
|
39
|
+
sfo_single_attr?(method) or sfo_multiple_attr?(method)
|
40
|
+
end
|
41
|
+
|
42
|
+
def sfo_single_attr?(method)
|
43
|
+
method.to_s[sfo_single_attr_regexp] ? true : false
|
44
|
+
end
|
45
|
+
|
46
|
+
def sfo_multiple_attr?(string)
|
47
|
+
string.to_s[sfo_multiple_attr_regexp] ? true : false
|
48
|
+
end
|
49
|
+
|
50
|
+
def sfo_date_attr?(tag_name)
|
51
|
+
tag_name.to_s[sfo_date_attr_regexp] ? true : false
|
52
|
+
end
|
53
|
+
|
54
|
+
def sfo_get_tag_name(object_name, method, multiple)
|
55
|
+
if sfo_multiple_attr?(object_name)
|
56
|
+
method.to_s[sfo_single_attr_regexp]
|
57
|
+
model_name = $1
|
58
|
+
attr_name = $2
|
59
|
+
tag_name = "#{object_name}[#{model_name}][][#{attr_name}]#{"[]" if multiple}"
|
60
|
+
elsif sfo_single_attr?(method)
|
61
|
+
method.to_s[sfo_single_attr_regexp]
|
62
|
+
model_name = $1
|
63
|
+
attr_name = $2
|
64
|
+
tag_name = "#{object_name}[#{model_name}][#{attr_name}]#{"[]" if multiple}"
|
65
|
+
end
|
66
|
+
|
67
|
+
tag_name
|
68
|
+
end
|
69
|
+
|
70
|
+
def sfo_get_method_name(method)
|
71
|
+
if sfo_single_attr?(method)
|
72
|
+
method.to_s[sfo_single_attr_regexp]
|
73
|
+
model_name = $1
|
74
|
+
attr_name = $2
|
75
|
+
method = "#{model_name}_#{attr_name}"
|
76
|
+
end
|
77
|
+
|
78
|
+
method
|
79
|
+
end
|
80
|
+
|
81
|
+
def sfo_get_date_tag_name(prefix, tag_name)
|
82
|
+
if sfo_multiple_attr?(prefix)
|
83
|
+
tag_name[sfo_date_attr_regexp]
|
84
|
+
model_name = $1
|
85
|
+
attr_name = $2
|
86
|
+
date_type = $3
|
87
|
+
tag_name = "#{prefix}[#{model_name}][][#{attr_name}#{date_type}]"
|
88
|
+
elsif tag_name[sfo_date_attr_regexp]
|
89
|
+
model_name = $1
|
90
|
+
attr_name = $2
|
91
|
+
date_type = $3
|
92
|
+
tag_name = "#{prefix}[#{model_name}][#{attr_name}#{date_type}]"
|
93
|
+
end
|
94
|
+
|
95
|
+
tag_name
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class DateTimeSelector
|
100
|
+
include HelperMethods
|
101
|
+
|
102
|
+
def input_name_from_type(type)
|
103
|
+
prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
|
104
|
+
prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
|
105
|
+
|
106
|
+
field_name = @options[:field_name] || type
|
107
|
+
if @options[:include_position]
|
108
|
+
field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
|
109
|
+
end
|
110
|
+
|
111
|
+
return sfo_get_date_tag_name(prefix, field_name) if sfo_date_attr?(field_name)
|
112
|
+
|
113
|
+
@options[:discard_type] ? prefix : "#{prefix}[#{field_name}]"
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
module Tags
|
119
|
+
class Base
|
120
|
+
include HelperMethods
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def value(object)
|
125
|
+
method_name = sfo_get_method_name(@method_name)
|
126
|
+
object.public_send method_name if object
|
127
|
+
end
|
128
|
+
|
129
|
+
def tag_name(multiple = false, index = nil)
|
130
|
+
return sfo_get_tag_name(@object_name, sanitized_method_name, multiple) if sfo_attr?(sanitized_method_name)
|
131
|
+
|
132
|
+
if index
|
133
|
+
"#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
|
134
|
+
else
|
135
|
+
"#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class FormBuilder
|
142
|
+
include HelperMethods
|
143
|
+
end
|
144
|
+
|
145
|
+
module FormHelper
|
146
|
+
include HelperMethods
|
147
|
+
|
148
|
+
def fields_for(record_name, record_object = nil, options = {}, &block)
|
149
|
+
if options[:sfo_multiple]
|
150
|
+
record_name[/^([\s\S]+)(\[[\s\S]+\])/]
|
151
|
+
part_1 = $1
|
152
|
+
part_2 = $2
|
153
|
+
record_name = "#{part_1}[sfo-multiple]#{part_2}"
|
154
|
+
end
|
155
|
+
builder = instantiate_builder(record_name, record_object, options)
|
156
|
+
capture(builder, &block)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module HelperMethods
|
2
2
|
def snake(string)
|
3
|
+
string = string.to_s
|
3
4
|
string.gsub!(/((\w)([A-Z]))/,'\2_\3')
|
4
5
|
class_name_if_module(string.downcase)
|
5
6
|
end
|
@@ -8,4 +9,12 @@ module HelperMethods
|
|
8
9
|
return $1 if string =~ /^.+::(.+)$/
|
9
10
|
string
|
10
11
|
end
|
12
|
+
|
13
|
+
def get_self_object(model)
|
14
|
+
method( snake(model.to_s).to_sym ).call
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_class_of_snake_model_name(snake_model_name)
|
18
|
+
Object.const_get( snake_model_name.to_s.split('_').map(&:capitalize).join )
|
19
|
+
end
|
11
20
|
end
|
@@ -1,163 +1,117 @@
|
|
1
|
+
require 'byebug'
|
2
|
+
|
1
3
|
module SlimFormObject
|
4
|
+
class Base
|
5
|
+
include ActiveModel::Model
|
6
|
+
include ::HelperMethods
|
7
|
+
extend ::HelperMethods
|
2
8
|
|
3
|
-
|
4
|
-
base.include ActiveModel::Model
|
5
|
-
base.include HelperMethods
|
6
|
-
base.extend ClassMethods
|
7
|
-
base.extend HelperMethods
|
8
|
-
end
|
9
|
+
attr_accessor :params, :array_objects_for_save, :hash_objects_for_save
|
9
10
|
|
10
|
-
|
11
|
+
class << self
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
define_method(:array_of_models) { args }
|
13
|
+
def set_model_name(name)
|
14
|
+
define_method(:model_name) { ActiveModel::Name.new(self, nil, name) }
|
15
15
|
end
|
16
|
-
add_attributes(args)
|
17
|
-
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
delegate attr.to_sym, "#{attr}=".to_sym,
|
28
|
-
to: snake(model.to_s).to_sym,
|
29
|
-
prefix: snake(model.to_s).to_sym
|
17
|
+
def init_single_models(*args)
|
18
|
+
define_array_of_models(:array_of_all_models, args)
|
19
|
+
end
|
20
|
+
alias_method :init_models, :init_single_models
|
21
|
+
|
22
|
+
def not_save_this_model(*args)
|
23
|
+
self.instance_eval do
|
24
|
+
define_method(:not_validate_this_models) { args }
|
30
25
|
end
|
31
26
|
end
|
32
|
-
end
|
33
27
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
def force_save_if_all_attr_is_nil(*args)
|
29
|
+
self.instance_eval do
|
30
|
+
define_method(:force_save_if_all_attr_is_nil) { args }
|
31
|
+
end
|
32
|
+
end
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
self
|
46
|
-
end
|
34
|
+
def define_array_of_models(name, args)
|
35
|
+
self.instance_eval do
|
36
|
+
define_method(name) { args }
|
37
|
+
end
|
38
|
+
make_methods_for_objects_of(args)
|
39
|
+
end
|
47
40
|
|
48
|
-
|
41
|
+
def make_methods_for_objects_of(models)
|
42
|
+
models.each{ |model| attr_accessor snake(model.to_s).to_sym }
|
43
|
+
|
44
|
+
delegate_models_attributes(models)
|
45
|
+
end
|
49
46
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
def delegate_models_attributes(models)
|
48
|
+
models.each do |model|
|
49
|
+
model.column_names.each do |attr|
|
50
|
+
delegate attr.to_sym, "#{attr}=".to_sym, to: snake(model.to_s).to_sym, prefix: true
|
51
|
+
end
|
52
|
+
end
|
55
53
|
end
|
56
|
-
return true
|
57
54
|
end
|
58
|
-
false
|
59
|
-
end
|
60
55
|
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
def initialize(params: {})
|
57
|
+
self.params = params
|
58
|
+
get_or_add_default_objects
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_or_add_default_objects
|
62
|
+
array_of_all_models.map do |model|
|
63
|
+
if get_self_object(model) == nil
|
64
|
+
method( "#{snake(model.to_s)}=" ).call(model.new)
|
65
|
+
else
|
66
|
+
get_self_object(model)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
# INIT END
|
64
71
|
|
65
|
-
private
|
66
72
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
73
|
+
def apply_parameters
|
74
|
+
check_array_settings_with_settings
|
75
|
+
apply
|
76
|
+
end
|
77
|
+
alias_method :submit, :apply_parameters
|
71
78
|
|
72
|
-
|
73
|
-
|
74
|
-
self_object_of_model1.save!
|
75
|
-
elsif association == :has_many or association == :has_and_belongs_to_many
|
76
|
-
self_object_of_model1.method("#{model2.table_name}").call << self_object_of_model2
|
77
|
-
self_object_of_model1.save!
|
79
|
+
def save
|
80
|
+
Saver.new(self).save
|
78
81
|
end
|
79
|
-
end
|
80
82
|
|
81
|
-
|
82
|
-
|
83
|
-
set_errors( method(snake(model.to_s)).call.errors ) unless method( snake(model.to_s) ).call.valid?
|
83
|
+
def validation_models
|
84
|
+
Validator.new(self).validate_form_object
|
84
85
|
end
|
85
|
-
end
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
# POMOGAY
|
88
|
+
|
89
|
+
def apply
|
90
|
+
assign = Assign.new(self)
|
91
|
+
@hash_objects_for_save = assign.apply_parameters
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_array_settings_with_settings
|
95
|
+
define_singleton_method(:not_save_this_model) { [] } unless respond_to?(:not_validate_this_model)
|
96
|
+
define_singleton_method(:force_save_if_all_attr_is_nil) { [] } unless respond_to?(:force_save_if_all_attr_is_nil)
|
90
97
|
end
|
91
|
-
end
|
92
98
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
99
|
+
def set_errors(object_errors)
|
100
|
+
object_errors.each do |attribute, message|
|
101
|
+
errors.add(attribute, message)
|
102
|
+
end
|
97
103
|
end
|
98
|
-
end
|
99
104
|
|
100
|
-
|
101
|
-
|
102
|
-
assign_attributes_for_collection(model)
|
105
|
+
def array_all_objects_for_save
|
106
|
+
array_objects_for_save ||= get_or_add_default_objects
|
103
107
|
end
|
104
|
-
end
|
105
108
|
|
106
|
-
def keys_of_collections
|
107
|
-
@keys ||= []
|
108
|
-
params.keys.each do |key|
|
109
|
-
@array_of_models.each do |model|
|
110
|
-
self_object_of_model = method( snake(model.to_s) ).call
|
111
|
-
method_name = key.to_s[/#{snake(model.to_s)}_(.*)/, 1]
|
112
|
-
@keys << method_name if self_object_of_model.respond_to? method_name.to_s
|
113
|
-
end if key[/^.+_ids$/]
|
114
|
-
end if @keys.empty?
|
115
|
-
@keys
|
116
109
|
end
|
110
|
+
end
|
117
111
|
|
118
|
-
def exist_any_errors_without_collections?
|
119
|
-
keys_of_collections.each do |method_name|
|
120
|
-
@array_of_models.each do |model|
|
121
|
-
name_of_model = method_name.to_s[/^(.+)_ids$/, 1]
|
122
|
-
name_of_constant_model = name_of_model.split('_').map(&:capitalize).join
|
123
|
-
name_of_key_error = Object.const_get(name_of_constant_model).table_name
|
124
|
-
errors.messages.delete(name_of_key_error.to_sym)
|
125
|
-
end
|
126
|
-
end unless valid?
|
127
|
-
errors.messages.empty?
|
128
|
-
end
|
129
112
|
|
130
|
-
def assign_attributes_for_collection(model)
|
131
|
-
self_object_of_model = method( snake(model.to_s) ).call
|
132
113
|
|
133
|
-
keys_of_collections.each do |method_name|
|
134
|
-
if self_object_of_model.respond_to? method_name
|
135
|
-
old_attribute = self_object_of_model.method( method_name ).call
|
136
|
-
unless self_object_of_model.update_attributes( {method_name.to_s => params["#{snake(model.to_s)}_#{method_name}".to_sym]} )
|
137
|
-
set_errors(self_object_of_model.errors)
|
138
|
-
self_object_of_model.update_attributes( {method_name.to_s => old_attribute} )
|
139
|
-
end if exist_any_errors_without_collections?
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
114
|
|
144
|
-
def make_attributes_of_model(model)
|
145
|
-
model_attributes = []
|
146
|
-
model.column_names.each do |name|
|
147
|
-
model_attributes << "#{snake(model.to_s)}_#{name}"
|
148
|
-
end
|
149
|
-
model_attributes
|
150
|
-
end
|
151
115
|
|
152
|
-
def get_attributes_for_update(model_attributes, model)
|
153
|
-
update_attributes = {}
|
154
|
-
hash_attributes = params.slice(*model_attributes)
|
155
|
-
hash_attributes.each{ |attr, val| update_attributes[attr.gsub(/#{snake(model.to_s)}_(.*)/, '\1')] = val }
|
156
|
-
update_attributes
|
157
|
-
end
|
158
116
|
|
159
|
-
def get_association(class1, class2)
|
160
|
-
class1.reflections.slice(snake(class2.to_s), class2.table_name).values.first&.macro
|
161
|
-
end
|
162
117
|
|
163
|
-
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module SlimFormObject
|
2
|
+
class Saver
|
3
|
+
include ::HelperMethods
|
4
|
+
|
5
|
+
attr_reader :form_object, :params, :validator, :hash_objects_for_save
|
6
|
+
|
7
|
+
def initialize(form_object)
|
8
|
+
@form_object = form_object
|
9
|
+
@params = form_object.params
|
10
|
+
@hash_objects_for_save = form_object.hash_objects_for_save
|
11
|
+
@validator = Validator.new(form_object)
|
12
|
+
end
|
13
|
+
|
14
|
+
def save
|
15
|
+
if form_object.valid?
|
16
|
+
ActiveRecord::Base.transaction do
|
17
|
+
save_main_objects
|
18
|
+
save_nested_objects
|
19
|
+
end
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
false
|
23
|
+
rescue
|
24
|
+
# p "ERROR"
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_main_objects
|
29
|
+
objects = Array.new(hash_objects_for_save[:objects])
|
30
|
+
while object_1 = objects.delete( objects[0] )
|
31
|
+
objects.each{ |object_2| save_objects(object_1, object_2) }
|
32
|
+
save_last_model_if_not_associations(object_1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_nested_objects
|
37
|
+
hash_objects_for_save[:objects].each do |object_1|
|
38
|
+
next unless hash_objects_for_save[:nested_objects].include?( snake(object_1.class).to_sym )
|
39
|
+
hash_objects_for_save[:nested_objects][snake(object_1.class).to_sym].each do |object_2|
|
40
|
+
save_objects(object_1, object_2)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def save_objects(object_1, object_2)
|
46
|
+
object_for_save = to_bind_models(object_1, object_2)
|
47
|
+
save_object(object_for_save)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_bind_models(object_1, object_2)
|
51
|
+
association = get_association(object_1.class, object_2.class)
|
52
|
+
|
53
|
+
if association == :belongs_to or association == :has_one
|
54
|
+
object_1.send( "#{snake(object_2.class.to_s)}=", object_2 )
|
55
|
+
elsif association == :has_many or association == :has_and_belongs_to_many
|
56
|
+
object_1.method("#{object_2.class.table_name}").call << object_2
|
57
|
+
end
|
58
|
+
|
59
|
+
object_1
|
60
|
+
end
|
61
|
+
|
62
|
+
def save_object(object_of_model)
|
63
|
+
if validator.valid_model_for_save?(object_of_model.class)
|
64
|
+
object_of_model.save!
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def save_last_model_if_not_associations(object_1)
|
69
|
+
association_trigger = false
|
70
|
+
hash_objects_for_save[:objects].each { |object_2| association_trigger = true if get_association(object_1.class, object_2.class) }
|
71
|
+
object_1.save unless association_trigger
|
72
|
+
rescue
|
73
|
+
object_1.class.find(object_1.id).update!(object_1.attributes)
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_association(class1, class2)
|
77
|
+
class1.reflections.slice(snake(class2.to_s), class2.table_name).values.first&.macro
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
# require 'byebug'
|
10
|
+
|
11
|
+
# module SlimFormObject
|
12
|
+
# class Base
|
13
|
+
# attr_accessor :params
|
14
|
+
|
15
|
+
# def self.init_models(*args)
|
16
|
+
# self.instance_eval do
|
17
|
+
# define_method(:array_of_single_models) { args }
|
18
|
+
# end
|
19
|
+
# add_attributes(args)
|
20
|
+
# end
|
21
|
+
|
22
|
+
# alias_method :init_single_models, :init_models
|
23
|
+
|
24
|
+
# def self.init_multiple_models(*args)
|
25
|
+
# self.instance_eval do
|
26
|
+
# define_method(:array_multiple_models) { args }
|
27
|
+
# end
|
28
|
+
# add_attributes(args)
|
29
|
+
# end
|
30
|
+
|
31
|
+
# def self.add_attributes(models)
|
32
|
+
# #acessors for model objects
|
33
|
+
# models.each{ |model| attr_accessor snake(model.to_s).to_sym }
|
34
|
+
|
35
|
+
# #delegate attributes of models
|
36
|
+
# models.each do |model|
|
37
|
+
# model.column_names.each do |attr|
|
38
|
+
# delegate attr.to_sym, "#{attr}=".to_sym, to: snake(model.to_s).to_sym,
|
39
|
+
# prefix: true
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
|
44
|
+
# def self.set_model_name(name)
|
45
|
+
# define_method(:model_name) { ActiveModel::Name.new(self, nil, name) }
|
46
|
+
# end
|
47
|
+
# # def initializer
|
48
|
+
|
49
|
+
# # end
|
50
|
+
# end
|
51
|
+
|
52
|
+
# def self.included(base)
|
53
|
+
# # define_properties(base)
|
54
|
+
|
55
|
+
# base.include ActiveModel::Model
|
56
|
+
# base.include HelperMethods
|
57
|
+
# base.extend ClassMethods
|
58
|
+
# base.extend HelperMethods
|
59
|
+
# end
|
60
|
+
|
61
|
+
# # def self.define_properties(form_object_klass)
|
62
|
+
# # class << form_object_klass
|
63
|
+
# # #attr_accessor for models and env params
|
64
|
+
# # # attr_accessor :params
|
65
|
+
|
66
|
+
# # # byebug
|
67
|
+
|
68
|
+
# # # def params=(val)
|
69
|
+
# # # @params = val
|
70
|
+
# # # end
|
71
|
+
|
72
|
+
# # # def params
|
73
|
+
# # # @params
|
74
|
+
# # # end
|
75
|
+
# # end
|
76
|
+
# # end
|
77
|
+
|
78
|
+
# # module ClassMethods
|
79
|
+
|
80
|
+
# # def init_models(*args)
|
81
|
+
# # self.instance_eval do
|
82
|
+
# # define_method(:array_of_single_models) { args }
|
83
|
+
# # end
|
84
|
+
# # add_attributes(args)
|
85
|
+
# # end
|
86
|
+
|
87
|
+
# # alias_method :init_single_models, :init_models
|
88
|
+
|
89
|
+
# # def init_multiple_models(*args)
|
90
|
+
# # self.instance_eval do
|
91
|
+
# # define_method(:array_multiple_models) { args }
|
92
|
+
# # end
|
93
|
+
# # add_attributes(args)
|
94
|
+
# # end
|
95
|
+
|
96
|
+
# # def add_attributes(models)
|
97
|
+
# # #acessors for model objects
|
98
|
+
# # models.each{ |model| attr_accessor snake(model.to_s).to_sym }
|
99
|
+
|
100
|
+
# # #delegate attributes of models
|
101
|
+
# # models.each do |model|
|
102
|
+
# # model.column_names.each do |attr|
|
103
|
+
# # delegate attr.to_sym, "#{attr}=".to_sym, to: snake(model.to_s).to_sym,
|
104
|
+
# # prefix: true
|
105
|
+
# # end
|
106
|
+
# # end
|
107
|
+
# # end
|
108
|
+
|
109
|
+
# # def set_model_name(name)
|
110
|
+
# # define_method(:model_name) { ActiveModel::Name.new(self, nil, name) }
|
111
|
+
# # end
|
112
|
+
# # end
|
113
|
+
|
114
|
+
# def submit
|
115
|
+
# @array_of_single_models ||= array_of_single_models.reject do |model|
|
116
|
+
# array_of_single_models_without_validates.include?(model) if self.respond_to?(:array_of_single_models_without_validates)
|
117
|
+
# end
|
118
|
+
# update_attributes
|
119
|
+
# update_attributes_for_collection
|
120
|
+
# self
|
121
|
+
# end
|
122
|
+
|
123
|
+
# alias_method :apply_parameters, :submit
|
124
|
+
|
125
|
+
# def save
|
126
|
+
# if valid?
|
127
|
+
# models = Array.new(@array_of_single_models)
|
128
|
+
# while model1 = models.delete( models[0] )
|
129
|
+
# models.each{ |model2| save_models(model1, model2) }
|
130
|
+
# save_last_model_if_not_associations(model1) if models.empty?
|
131
|
+
# end
|
132
|
+
# return true
|
133
|
+
# end
|
134
|
+
# false
|
135
|
+
# end
|
136
|
+
|
137
|
+
# def not_validate(*args)
|
138
|
+
# define_singleton_method(:array_of_single_models_without_validates) { args }
|
139
|
+
# end
|
140
|
+
|
141
|
+
# private
|
142
|
+
|
143
|
+
# def save_models(model_1, model_2)
|
144
|
+
# self_object_of_model_for_save = nil
|
145
|
+
# byebug
|
146
|
+
# if both_model_attributes_exist?(model_1, model_2)
|
147
|
+
# # byebug
|
148
|
+
# self_object_of_model_for_save = to_bind_models(model_1, model_2)
|
149
|
+
# save_model(self_object_of_model_for_save)
|
150
|
+
# else
|
151
|
+
# get_self_objects_of_model(model_1, model_2).each do |object|
|
152
|
+
# save_model(object)
|
153
|
+
# end
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
|
157
|
+
# def to_bind_models(model_1, model_2)
|
158
|
+
# self_object_of_model_1, self_object_of_model_2 = get_self_objects_of_model(model_1, model_2)
|
159
|
+
# association = get_association(model_1, model_2)
|
160
|
+
|
161
|
+
# if association == :belongs_to or association == :has_one
|
162
|
+
# self_object_of_model_1.send( "#{snake(model_2.to_s)}=", self_object_of_model_2 )
|
163
|
+
# elsif association == :has_many or association == :has_and_belongs_to_many
|
164
|
+
# self_object_of_model_1.method("#{model_2.table_name}").call << self_object_of_model_2
|
165
|
+
# end
|
166
|
+
|
167
|
+
# self_object_of_model_1
|
168
|
+
# end
|
169
|
+
|
170
|
+
# def valid_model_for_save?(model)
|
171
|
+
# ( (attributes_is_present?(model) and method( snake(model.to_s) ).call.id != nil) or (method( snake(model.to_s) ).call.id == nil and !all_attributes_is_empty?(model)) )
|
172
|
+
# end
|
173
|
+
|
174
|
+
# def attributes_is_present?(model)
|
175
|
+
# (make_attributes_of_model(model) & params.keys).present?
|
176
|
+
# end
|
177
|
+
|
178
|
+
# def both_model_attributes_exist?(model_1, model_2)
|
179
|
+
# valid_model_for_save?(model_1) and valid_model_for_save?(model_2)
|
180
|
+
# end
|
181
|
+
|
182
|
+
# def save_model(self_object_of_model)
|
183
|
+
# if valid_model_for_save?(self_object_of_model.class)
|
184
|
+
# self_object_of_model.save!
|
185
|
+
# end
|
186
|
+
# end
|
187
|
+
|
188
|
+
# def all_attributes_is_empty?(model)
|
189
|
+
# is_empty = true
|
190
|
+
# array_symbols_of_attributes = (make_attributes_of_model(model) & params.keys).map { |attr| attr.to_sym }
|
191
|
+
# params.slice(*array_symbols_of_attributes).values.each do |value|
|
192
|
+
# is_empty = false unless value == ""
|
193
|
+
# end
|
194
|
+
# is_empty
|
195
|
+
# end
|
196
|
+
|
197
|
+
# def get_self_objects_of_model(model_1, model_2)
|
198
|
+
# [ method( snake(model_1.to_s) ).call, method( snake(model_2.to_s) ).call ]
|
199
|
+
# end
|
200
|
+
|
201
|
+
# def save_last_model_if_not_associations(model)
|
202
|
+
# association_trigger = false
|
203
|
+
# self_object_of_model = method( snake(model.to_s) ).call
|
204
|
+
# @array_of_single_models.each { |model2| association_trigger = true if get_association(model, model2) }
|
205
|
+
# self_object_of_model.save unless association_trigger
|
206
|
+
# rescue
|
207
|
+
# self_object_of_model.class.find(self_object_of_model.id).update!(self_object_of_model.attributes)
|
208
|
+
# end
|
209
|
+
|
210
|
+
# def validation_models
|
211
|
+
# @array_of_single_models.each do |model|
|
212
|
+
# next unless valid_model_for_save?(model)
|
213
|
+
# set_errors( method(snake(model.to_s)).call.errors ) unless method( snake(model.to_s) ).call.valid?
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
|
217
|
+
# def set_errors(model_errors)
|
218
|
+
# model_errors.each do |attribute, message|
|
219
|
+
# errors.add(attribute, message)
|
220
|
+
# end
|
221
|
+
# end
|
222
|
+
|
223
|
+
# def update_attributes
|
224
|
+
# @array_of_single_models.each do |model|
|
225
|
+
# model_attributes = make_attributes_of_model(model)
|
226
|
+
# method( snake(model.to_s) ).call.assign_attributes( get_attributes_for_update(model_attributes, model) )
|
227
|
+
# end
|
228
|
+
# end
|
229
|
+
|
230
|
+
# def update_attributes_for_collection
|
231
|
+
# @array_of_single_models.each do |model|
|
232
|
+
# assign_attributes_for_collection(model)
|
233
|
+
# end
|
234
|
+
# end
|
235
|
+
|
236
|
+
# def keys_of_collections
|
237
|
+
# @keys ||= []
|
238
|
+
# params.keys.each do |key|
|
239
|
+
# @array_of_single_models.each do |model|
|
240
|
+
# self_object_of_model = method( snake(model.to_s) ).call
|
241
|
+
# method_name = key.to_s[/#{snake(model.to_s)}_(.*)/, 1]
|
242
|
+
# @keys << method_name if self_object_of_model.respond_to? method_name.to_s
|
243
|
+
# end if key[/^.+_ids$/]
|
244
|
+
# end if @keys.empty?
|
245
|
+
# @keys
|
246
|
+
# end
|
247
|
+
|
248
|
+
# def exist_any_errors_without_collections?
|
249
|
+
# keys_of_collections.each do |method_name|
|
250
|
+
# @array_of_single_models.each do |model|
|
251
|
+
# name_of_model = method_name.to_s[/^(.+)_ids$/, 1]
|
252
|
+
# name_of_constant_model = name_of_model.split('_').map(&:capitalize).join
|
253
|
+
# name_of_key_error = Object.const_get(name_of_constant_model).table_name
|
254
|
+
# errors.messages.delete(name_of_key_error.to_sym)
|
255
|
+
# end
|
256
|
+
# end unless valid?
|
257
|
+
# errors.messages.empty?
|
258
|
+
# end
|
259
|
+
|
260
|
+
# def assign_attributes_for_collection(model)
|
261
|
+
# self_object_of_model = method( snake(model.to_s) ).call
|
262
|
+
|
263
|
+
# keys_of_collections.each do |method_name|
|
264
|
+
# if self_object_of_model.respond_to? method_name
|
265
|
+
# old_attribute = self_object_of_model.method( method_name ).call
|
266
|
+
# unless self_object_of_model.update_attributes( {method_name.to_s => params["#{snake(model.to_s)}_#{method_name}".to_sym]} )
|
267
|
+
# set_errors(self_object_of_model.errors)
|
268
|
+
# self_object_of_model.update_attributes( {method_name.to_s => old_attribute} )
|
269
|
+
# end if exist_any_errors_without_collections?
|
270
|
+
# end
|
271
|
+
# end
|
272
|
+
# end
|
273
|
+
|
274
|
+
# def make_attributes_of_model(model)
|
275
|
+
# model_attributes = []
|
276
|
+
# model.column_names.each do |name|
|
277
|
+
# model_attributes << "#{snake(model.to_s)}_#{name}"
|
278
|
+
# end
|
279
|
+
# model_attributes
|
280
|
+
# end
|
281
|
+
|
282
|
+
# def get_attributes_for_update(model_attributes, model)
|
283
|
+
# attributes_for_update = {}
|
284
|
+
# hash_attributes = params.slice(*model_attributes)
|
285
|
+
# hash_attributes.each{ |attr, val| attributes_for_update[attr.gsub(/#{snake(model.to_s)}_(.*)/, '\1')] = val }
|
286
|
+
# attributes_for_update
|
287
|
+
# end
|
288
|
+
|
289
|
+
# def get_association(class1, class2)
|
290
|
+
# class1.reflections.slice(snake(class2.to_s), class2.table_name).values.first&.macro
|
291
|
+
# end
|
292
|
+
|
293
|
+
|
294
|
+
# # get attributes
|
295
|
+
# # .gsub(/^\[|\]$|"/, '').split(', ')
|
296
|
+
|
297
|
+
# end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module SlimFormObject
|
2
|
+
class Validator
|
3
|
+
include ::HelperMethods
|
4
|
+
|
5
|
+
attr_reader :form_object, :params, :hash_objects_for_save
|
6
|
+
|
7
|
+
def initialize(form_object)
|
8
|
+
@form_object = form_object
|
9
|
+
@params = form_object.params
|
10
|
+
@hash_objects_for_save = form_object.hash_objects_for_save
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_form_object
|
14
|
+
filter_nil_objects
|
15
|
+
|
16
|
+
hash_objects_for_save[:objects].each do |object|
|
17
|
+
next if all_attributes_is_nil?(object)
|
18
|
+
form_object.set_errors( object.errors ) unless object.valid?
|
19
|
+
end
|
20
|
+
|
21
|
+
hash_objects_for_save[:nested_objects].keys.each do |snake_model_name|
|
22
|
+
hash_objects_for_save[:nested_objects][snake_model_name].each do |object|
|
23
|
+
form_object.set_errors( object.errors ) unless object.valid?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def filter_nil_objects
|
29
|
+
hash_objects_for_save[:objects].reject! do |object|
|
30
|
+
all_attributes_is_nil?(object)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid_model_for_save?(object)
|
35
|
+
# ( (attributes_is_present?(object) and object.id != nil) or (object.id == nil and !all_attributes_is_empty?(object)) )
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def both_model_attributes_exist?(object_1, object_2)
|
40
|
+
# valid_model_for_save?(object_1) and valid_model_for_save?(object_2)
|
41
|
+
!(all_attributes_is_nil?(object_1) and all_attributes_is_nil?(object_2))
|
42
|
+
end
|
43
|
+
|
44
|
+
def all_attributes_is_nil?(object)
|
45
|
+
object.class.column_names.each do |attr_name|
|
46
|
+
return false if object.send(attr_name.to_sym) != nil
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
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: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- woodcrust
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 5.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 5.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: 5.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: 5.0.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,8 +161,13 @@ extra_rdoc_files: []
|
|
147
161
|
files:
|
148
162
|
- bin/slim_form_object
|
149
163
|
- lib/slim_form_object.rb
|
164
|
+
- lib/slim_form_object/assign.rb
|
165
|
+
- lib/slim_form_object/form_helpers/extension_actionview.rb
|
150
166
|
- lib/slim_form_object/helpers.rb
|
151
167
|
- lib/slim_form_object/processing.rb
|
168
|
+
- lib/slim_form_object/saver.rb
|
169
|
+
- lib/slim_form_object/tmp.rb
|
170
|
+
- lib/slim_form_object/validator.rb
|
152
171
|
- lib/slim_form_object/version.rb
|
153
172
|
- spec/db/database.yml
|
154
173
|
- spec/db/database.yml.travis
|