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