tramway-core 1.17.1 → 1.17.2.3

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -2
  3. data/app/assets/javascripts/tramway/core/application.js +1 -1
  4. data/app/controllers/tramway/core/application_controller.rb +8 -12
  5. data/app/decorators/tramway/core/application_decorator.rb +16 -28
  6. data/app/decorators/tramway/core/associations/class_helper.rb +13 -13
  7. data/app/decorators/tramway/core/associations/object_helper.rb +31 -3
  8. data/app/decorators/tramway/core/attributes/view_helper.rb +26 -0
  9. data/app/decorators/tramway/core/concerns/attributes_decorator_helper.rb +47 -26
  10. data/app/decorators/tramway/core/delegating/class_helper.rb +9 -0
  11. data/app/forms/tramway/core/application_form.rb +83 -171
  12. data/app/forms/tramway/core/application_forms/association_object_helpers.rb +31 -0
  13. data/app/forms/tramway/core/application_forms/constant_class_actions.rb +7 -0
  14. data/app/forms/tramway/core/application_forms/constant_object_actions.rb +13 -0
  15. data/app/forms/tramway/core/application_forms/properties_object_helper.rb +23 -0
  16. data/app/forms/tramway/core/extendable_form.rb +3 -70
  17. data/app/forms/tramway/core/extendable_forms_helpers/class_builder.rb +34 -0
  18. data/app/forms/tramway/core/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
  19. data/app/forms/tramway/core/extendable_forms_helpers/more_properties_helper.rb +27 -0
  20. data/app/forms/tramway/core/extendable_forms_helpers/properties_helper.rb +16 -0
  21. data/app/forms/tramway/core/extendable_forms_helpers/submit/class_helpers.rb +18 -0
  22. data/app/forms/tramway/core/extendable_forms_helpers/submit/object_helpers.rb +7 -0
  23. data/app/forms/tramway/core/extendable_forms_helpers/validators.rb +40 -0
  24. data/app/helpers/tramway/core/copy_to_clipboard_helper.rb +6 -10
  25. data/app/helpers/tramway/core/title_helper.rb +17 -22
  26. data/app/models/tramway/core/application_record.rb +38 -40
  27. data/app/uploaders/image_defaults.rb +2 -1
  28. data/app/uploaders/photo_uploader.rb +8 -8
  29. data/config/initializers/plurals.rb +2 -2
  30. data/lib/tramway/collection.rb +4 -6
  31. data/lib/tramway/collections.rb +4 -0
  32. data/lib/tramway/collections/helper.rb +15 -14
  33. data/lib/tramway/core.rb +22 -22
  34. data/lib/tramway/core/engine.rb +4 -8
  35. data/lib/tramway/core/generators.rb +4 -0
  36. data/lib/tramway/core/generators/install_generator.rb +17 -17
  37. data/lib/tramway/core/version.rb +1 -1
  38. data/lib/tramway/error.rb +12 -1
  39. data/lib/yaml/errors.yml +35 -0
  40. metadata +20 -3
@@ -1,204 +1,116 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Tramway::Core
4
- class ApplicationForm < ::Reform::Form
5
- def initialize(object = nil)
6
- object ||= self.class.model_class.new
7
- super(object).tap do
8
- @@model_class = object.class
9
- @@enumerized_attributes = object.class.try :enumerized_attributes
10
- @@associations ||= []
11
-
12
- self.class.full_class_name_associations.each do |association, class_name|
13
- if class_name.is_a? Array
14
- self.class.send(:define_method, "#{association}=") do |value|
15
- association_class = send("#{association}_type")
16
- if association_class.nil?
17
- raise Tramway::Error.new(plugin: :core, method: :initialize, message: 'Polymorphic association class is nil. Maybe, you should write `assocation #{association_name}` after `properties #{association_name}_id, #{association_name}_type`')
18
- else
19
- super association_class.constantize.find value
20
- end
21
- end
22
- else
23
- self.class.send(:define_method, "#{association}=") do |value|
24
- super class_name.find value
25
- end
26
- end
27
- end
28
-
29
- delegating object
3
+ class Tramway::Core::ApplicationForm < ::Reform::Form
4
+ include Tramway::Core::ApplicationForms::AssociationObjectHelpers
5
+ include Tramway::Core::ApplicationForms::ConstantObjectActions
6
+ include Tramway::Core::ApplicationForms::PropertiesObjectHelper
7
+
8
+ def initialize(object = nil)
9
+ object ||= self.class.model_class.new
10
+ super(object).tap do
11
+ @@model_class = object.class
12
+ @@enumerized_attributes = object.class.try :enumerized_attributes
13
+ @@associations ||= []
14
+
15
+ self.class.full_class_name_associations&.each do |association, class_name|
16
+ define_association_method association, class_name
30
17
  end
31
- end
32
18
 
33
- def submit(params)
34
- if params
35
- if validate params
36
- begin
37
- save.tap do
38
- # self.class.remove_validations_from_model!
39
- end
40
- rescue StandardError => e
41
- # self.class.remove_validations_from_model!
42
- error = Tramway::Error.new(plugin: :core, method: :submit, message: "Looks like you have method `#{e.name.to_s.gsub('=', '')}` in #{@@model_class}. You should rename it or rename property in #{self.class}")
43
- raise error.message
44
- end
45
- else
46
- association_error = false
47
- @@associations.each do |association|
48
- if errors.details[association] == [{ error: :blank }]
49
- model.send("#{association}=", send(association))
50
- association_error = true
51
- end
52
- end
53
- (association_error && save).tap do
54
- # self.class.remove_validations_from_model!
55
- end
56
- end
57
- else
58
- # self.class.remove_validations_from_model!
59
- error = Tramway::Error.new(plugin: :core, method: :submit, message: 'ApplicationForm::Params should not be nil')
60
- raise error.message
61
- end
19
+ delegating object
62
20
  end
21
+ end
63
22
 
64
- def model_name
65
- @@model_class.model_name
23
+ def submit(params)
24
+ if params
25
+ validate(params) ? save : collecting_associations_errors
26
+ else
27
+ Tramway::Error.raise_error(:tramway, :core, :application_form, :submit, :params_should_not_be_nil)
66
28
  end
29
+ end
67
30
 
68
- def associations
69
- @@associations
70
- end
31
+ def model_name
32
+ @@model_class.model_name
33
+ end
71
34
 
72
- def form_properties(**args)
73
- @form_properties = args
74
- end
35
+ class << self
36
+ include Tramway::Core::ApplicationForms::ConstantClassActions
75
37
 
76
- def form_properties_additional(**args)
77
- @form_properties_additional = args
78
- end
38
+ delegate :defined_enums, to: :model_class
79
39
 
80
- def properties
81
- return @form_properties if @form_properties
40
+ def association(property)
41
+ properties property
42
+ @@associations = ((defined?(@@associations) && @@associations) || []) + [property]
43
+ end
82
44
 
83
- yaml_config_file_path = Rails.root.join('app', 'forms', "#{self.class.name.underscore}.yml")
84
- if File.exist? yaml_config_file_path
85
- @form_properties = YAML.load_file(yaml_config_file_path).deep_symbolize_keys
86
- @form_properties.deep_merge! @form_properties_additional if @form_properties_additional
87
- @form_properties
88
- else
89
- []
90
- end
45
+ def associations(*properties)
46
+ properties.each { |property| association property }
91
47
  end
92
48
 
93
- def build_errors; end
49
+ def full_class_name_associations
50
+ @@associations&.reduce({}) do |hash, association|
51
+ options = @@model_class.reflect_on_all_associations(:belongs_to).select do |a|
52
+ a.name == association.to_sym
53
+ end.first&.options
94
54
 
95
- def delegating(object)
96
- methods = %i[to_key errors]
97
- methods.each do |method|
98
- self.class.send(:define_method, method) do
99
- object.send method
55
+ if options&.dig(:polymorphic)
56
+ hash.merge! association => @@model_class.send("#{association}_type").values
57
+ elsif options
58
+ hash.merge!(association => (options[:class_name] || association.to_s.camelize).constantize)
100
59
  end
60
+ hash
101
61
  end
102
62
  end
103
63
 
104
- def attributes
105
- properties.reduce({}) do |hash, property|
106
- hash.merge! property.first => model.values[property.first.to_s]
107
- end
64
+ def full_class_name_association(association_name)
65
+ full_class_name_associations[association_name]
108
66
  end
109
67
 
110
- class << self
111
- delegate :defined_enums, to: :model_class
112
-
113
- def association(property)
114
- properties property
115
- @@associations ||= []
116
- @@associations << property
117
- end
118
-
119
- def associations(*properties)
120
- properties.each do |property|
121
- association property
122
- end
123
- end
124
-
125
- def full_class_name_associations
126
- @@associations&.reduce({}) do |hash, association|
127
- options = @@model_class.reflect_on_all_associations(:belongs_to).select do |a|
128
- a.name == association.to_sym
129
- end.first&.options
130
-
131
- if options
132
- if options[:polymorphic]
133
- hash.merge! association => @@model_class.send("#{association}_type").values
134
- else
135
- class_name = options[:class_name] || association.to_s.camelize
136
- hash.merge!(association => class_name.constantize)
137
- end
138
- end
139
- hash
140
- end
141
- end
142
-
143
- def full_class_name_association(association_name)
144
- full_class_name_associations[association_name]
145
- end
146
-
147
- def enumerized_attributes
148
- @@enumerized_attributes
149
- end
68
+ def reflect_on_association(*args)
69
+ @@model_class.reflect_on_association(*args)
70
+ end
150
71
 
151
- def reflect_on_association(*args)
152
- @@model_class.reflect_on_association(*args)
153
- end
72
+ def enumerized_attributes
73
+ @@enumerized_attributes
74
+ end
154
75
 
155
- def model_class
156
- if defined?(@@model_class) && @@model_class
157
- @@model_class
158
- else
159
- model_class_name ||= name.to_s.sub(/Form$/, '')
160
- begin
161
- @@model_class = model_class_name.constantize
162
- rescue StandardError
163
- error = Tramway::Error.new(plugin: :core, method: :model_class, message: "There is not model class name for #{name}. Should be #{model_class_name} or you can use another class to initialize form object or just initialize form with object.")
164
- raise error.message
165
- end
76
+ def model_class
77
+ if defined?(@@model_class) && @@model_class
78
+ @@model_class
79
+ else
80
+ model_class_name ||= name.to_s.sub(/Form$/, '')
81
+ begin
82
+ @@model_class = model_class_name.constantize
83
+ rescue StandardError
84
+ Tramway::Error.raise_error :tramway, :core, :application_form, :model_class, :there_is_not_model_class,
85
+ name: name, model_class_name: model_class_name
166
86
  end
167
87
  end
88
+ end
168
89
 
169
- def model_class=(name)
170
- @@model_class = name
171
- end
90
+ def model_class=(name)
91
+ @@model_class = name
92
+ end
172
93
 
173
- def validation_group_class
174
- ActiveModel
94
+ def validates(attribute, **options)
95
+ if !defined?(@@model_class) || @@model_class.nil?
96
+ Tramway::Error.raise_error(:tramway, :core, :application_form, :validates, :you_need_to_set_model_class)
175
97
  end
98
+ @@model_class.validates attribute, **options
99
+ end
100
+ end
176
101
 
177
- def validates(attribute, **options)
178
- if !defined?(@@model_class) || @@model_class.nil?
179
- error = Tramway::Error.new(plugin: :core, method: :validates, message: 'You need to set `model_class` name while using validations. Just write `self.model_class = YOUR_MODEL_NAME` in the class area.')
180
- raise error.message
181
- end
182
- @@model_class.validates attribute, **options
183
- # @@validations ||= {}
184
- # @@validations.deep_merge! attribute => options
185
- end
102
+ private
186
103
 
187
- # FIXME: Removes all validations in a field. We must implement own validations
188
-
189
- # def remove_validations_from_model!
190
- # return unless defined? @@validations
191
- # @@validations&.each do |validation|
192
- # @@model_class.class_eval do
193
- # _validators.except validation[0]
194
- #
195
- # binding.pry
196
- # _validate_callbacks.each do |callback|
197
- # callback.raw_filter.attributes.delete validation[0]
198
- # end
199
- # end
200
- # end
201
- # end
104
+ def collecting_associations_errors
105
+ @@associations.each do |association|
106
+ model.send("#{association}=", send(association)) if errors.details[association] == [{ error: :blank }]
202
107
  end
203
108
  end
109
+
110
+ def save
111
+ super
112
+ rescue StandardError => e
113
+ Tramway::Error.raise_error :tramway, :core, :application_form, :submit, :looks_like_you_have_method,
114
+ method_name: e.name.to_s.gsub('=', ''), model_class: @@model_class, class_name: self.class
115
+ end
204
116
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ApplicationForms::AssociationObjectHelpers
4
+ def associations
5
+ @@associations
6
+ end
7
+
8
+ def define_association_method(association, class_name)
9
+ if class_name.is_a? Array
10
+ define_polymorphic_association association, class_name
11
+ else
12
+ self.class.send(:define_method, "#{association}=") do |value|
13
+ super class_name.find value
14
+ end
15
+ end
16
+ end
17
+
18
+ def define_polymorphic_association(association, _class_name)
19
+ self.class.send(:define_method, "#{association}=") do |value|
20
+ association_class = value.split('_')[0..-2].join('_').camelize
21
+ association_class = association_class.constantize if association_class.is_a? String
22
+ if association_class.nil?
23
+ Tramway::Error.raise_error :tramway, :core, :application_form, :initialize, :polymorphic_class_is_nil,
24
+ association_name: association
25
+ else
26
+ super association_class.find value.split('_')[-1]
27
+ send "#{association}_type=", association_class.to_s
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ApplicationForms::ConstantClassActions
4
+ def validation_group_class
5
+ ActiveModel
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ApplicationForms::ConstantObjectActions
4
+ def delegating(object)
5
+ %i[to_key errors].each { |method| self.class.send(:define_method, method) { object.send method } }
6
+ end
7
+
8
+ def build_errors; end
9
+
10
+ def attributes
11
+ properties.reduce({}) { |hash, property| hash.merge! property.first => model.values[property.first.to_s] }
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ApplicationForms::PropertiesObjectHelper
4
+ def form_properties(**args)
5
+ @form_properties = args
6
+ end
7
+
8
+ def form_properties_additional(**args)
9
+ @form_properties_additional = args
10
+ end
11
+
12
+ def properties
13
+ return @form_properties if @form_properties
14
+
15
+ yaml_config_file_path = Rails.root.join('app', 'forms', "#{self.class.name.underscore}.yml")
16
+
17
+ return [] unless File.exist? yaml_config_file_path
18
+
19
+ @form_properties = YAML.load_file(yaml_config_file_path).deep_symbolize_keys
20
+ @form_properties.deep_merge! @form_properties_additional if @form_properties_additional
21
+ @form_properties
22
+ end
23
+ end
@@ -2,80 +2,13 @@
2
2
 
3
3
  class Tramway::Core::ExtendableForm
4
4
  class << self
5
+ include Tramway::Core::ExtendableFormsHelpers::ClassBuilder
6
+
5
7
  def new(name, simple_properties: {}, **more_properties)
6
8
  if Object.const_defined? name
7
9
  name.constantize
8
10
  else
9
- Object.const_set(name, Class.new(::Tramway::Core::ApplicationForm) do
10
- properties(*simple_properties.keys) if simple_properties.keys.any?
11
-
12
- define_method 'submit' do |params|
13
- model.values ||= {}
14
- extended_params = params.except(*simple_properties.keys).except(*jsonb_ignored_properties(more_properties))
15
- params.each do |key, value|
16
- method_name = "#{key}="
17
- send method_name, value if respond_to?(method_name)
18
- end
19
- model.values = extended_params.permit!.to_h.reduce(model.values) do |hash, pair|
20
- hash.merge! pair[0] => pair[1]
21
- end
22
- super params
23
- end
24
-
25
- define_method 'properties' do
26
- hash = simple_properties.each_with_object({}) do |property, h|
27
- h.merge! property[0] => property[1] unless model.class.state_machines.keys.include?(property[0])
28
- end
29
- more_properties.reduce(hash) do |h, property|
30
- h.merge! property[0] => {
31
- extended_form_property: property[1][:object]
32
- }
33
- end
34
- end
35
-
36
- more_properties.each do |property|
37
- define_method property[0] do
38
- model.values[property[0]] if model.values
39
- end
40
-
41
- case property[1][:object].field_type
42
- when 'file'
43
- field = property[1][:object]
44
- define_method "#{property[0]}=" do |value|
45
- file_instance = property[1][:association_model].find_or_create_by "#{model.class.name.underscore}_id" => model.id, "#{field.class.name.underscore}_id" => field.id
46
- file_instance.file = value
47
- file_instance.save!
48
- end
49
- else
50
- next unless property[1][:validates].present?
51
-
52
- define_method "#{property[0]}=" do |value|
53
- property[1][:validates].each do |pair|
54
- case pair[0].to_s
55
- when 'presence'
56
- validator_object = "#{pair[0].to_s.camelize}Validator".constantize.new(attributes: :not_blank)
57
- if pair[1] == 'true' && !validator_object.send(:valid?, value)
58
- model.errors.add property[0],
59
- I18n.t("activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{pair[0]}", value: value)
60
- end
61
- when 'inclusion'
62
- in_array = pair[1][:in]
63
- unless value.in? in_array
64
- model.errors.add property[0],
65
- I18n.t("activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{pair[0]}", value: value)
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
-
73
- define_method :jsonb_ignored_properties do |properties|
74
- properties.map do |property|
75
- property[0].to_s if property[1][:object].field_type == 'file'
76
- end.compact
77
- end
78
- end)
11
+ build_form_class name, simple_properties, more_properties
79
12
  end
80
13
  end
81
14
  end