tramway-core 1.17.1.1 → 1.17.2.4

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -2
  3. data/app/controllers/tramway/core/application_controller.rb +8 -12
  4. data/app/decorators/tramway/core/application_decorator.rb +16 -28
  5. data/app/decorators/tramway/core/associations/class_helper.rb +13 -13
  6. data/app/decorators/tramway/core/associations/object_helper.rb +31 -3
  7. data/app/decorators/tramway/core/attributes/view_helper.rb +26 -0
  8. data/app/decorators/tramway/core/concerns/attributes_decorator_helper.rb +47 -26
  9. data/app/decorators/tramway/core/delegating/class_helper.rb +9 -0
  10. data/app/forms/tramway/core/application_form.rb +83 -171
  11. data/app/forms/tramway/core/application_forms/association_object_helpers.rb +31 -0
  12. data/app/forms/tramway/core/application_forms/constant_class_actions.rb +7 -0
  13. data/app/forms/tramway/core/application_forms/constant_object_actions.rb +13 -0
  14. data/app/forms/tramway/core/application_forms/properties_object_helper.rb +23 -0
  15. data/app/forms/tramway/core/extendable_form.rb +3 -70
  16. data/app/forms/tramway/core/extendable_forms_helpers/class_builder.rb +34 -0
  17. data/app/forms/tramway/core/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
  18. data/app/forms/tramway/core/extendable_forms_helpers/more_properties_helper.rb +27 -0
  19. data/app/forms/tramway/core/extendable_forms_helpers/properties_helper.rb +16 -0
  20. data/app/forms/tramway/core/extendable_forms_helpers/submit/class_helpers.rb +18 -0
  21. data/app/forms/tramway/core/extendable_forms_helpers/submit/object_helpers.rb +7 -0
  22. data/app/forms/tramway/core/extendable_forms_helpers/validators.rb +40 -0
  23. data/app/helpers/tramway/core/copy_to_clipboard_helper.rb +6 -10
  24. data/app/helpers/tramway/core/title_helper.rb +17 -22
  25. data/app/models/tramway/core/application_record.rb +38 -40
  26. data/app/uploaders/image_defaults.rb +2 -1
  27. data/app/uploaders/photo_uploader.rb +8 -8
  28. data/config/initializers/plurals.rb +2 -2
  29. data/lib/tramway/collection.rb +4 -6
  30. data/lib/tramway/collections.rb +4 -0
  31. data/lib/tramway/collections/helper.rb +15 -14
  32. data/lib/tramway/core.rb +22 -22
  33. data/lib/tramway/core/engine.rb +4 -8
  34. data/lib/tramway/core/generators.rb +6 -0
  35. data/lib/tramway/core/generators/install_generator.rb +17 -17
  36. data/lib/tramway/core/version.rb +1 -1
  37. data/lib/tramway/error.rb +12 -1
  38. data/lib/yaml/errors.yml +35 -0
  39. metadata +20 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4be07671b875ed3901b13904f9d54f3915ab5c4c42d637609a25bebee8b233a0
4
- data.tar.gz: 77d1050db409315611f0fda8586c20cd15aa9b85e49d23f86ebc995556e420da
3
+ metadata.gz: b75d7e99e7440745ca0e69aeb6cfb0c3416f51aac3c56b50a670bde828d0a2af
4
+ data.tar.gz: 1690aa1dd010e6b14faf2e2aaf30d978ef198467c0a826936411070ee67ec30a
5
5
  SHA512:
6
- metadata.gz: 875d00ccf2b6cdfa9bdb7fb64ab77b60b517be9f4ae24f856b5e79e2e90c068d97f074ea4df90b70f70457dbbbd955525d850f3f6a5939ba404eec020d144fc6
7
- data.tar.gz: 3c0ffdef1b9dba8d41353908a82d2841879b9490d191e10ca017ed16d6b14bbabceeb5da27318dbf1939203820eed1d3227980e59f0410864e74785e48d85f68
6
+ metadata.gz: e80f2d56b1d3b10dff0f3f7231d9fef45044b9aa2c947ab56393176dda4e870f097434e43b1e40c37b3c8f6e8b7cd6d730ce2fe872d20a7f10c92b742c1be9f4
7
+ data.tar.gz: eac916585fb7b1d7fd8009e461ddc330625ca1a8b9f64079ee0e2fc90b0067fa88af413a8d9ddc2acbcb7f63185fe45d11a0773f6f321e59e64d5297257c83a7
data/README.md CHANGED
@@ -33,7 +33,53 @@ Tramway::Core.initialize_application model_class: ::Tramway::Conference::Unity #
33
33
  Rails.application.config.assets.precompile += %w( *.jpg *.png *.js )
34
34
  ```
35
35
  # Usage
36
+
36
37
  ## Decorators
38
+ ### Associations
39
+
40
+ Your can decorate association models. Supporting all types of association
41
+
42
+ *app/decorators/your_model_decorator.rb*
43
+ ```ruby
44
+ class YourModelDecorator < Tramway::Core::ApplicationDecorator
45
+ decorate_association :some_model
46
+ decorate_association :another_model, decorator: SpecificDecoratorForThisCase
47
+ decorate_association :another_one_model, as: :repeat_here_as_parameter_from_model
48
+ decorate_association :something_else_model, state_machines: [ :here_array_of_state_machines_you_want_to_see_in_YourModel_show_page ] # support from tramway-admin gem
49
+ end
50
+ ```
51
+
52
+ You can decorate a lot of models in one line
53
+
54
+ *app/decorators/your_model_decorator.rb*
55
+ ```ruby
56
+ class YourModelDecorator < Tramway::Core::ApplicationDecorator
57
+ decorate_associations :some_model, :another_model, :another_one_model, :something_else_model
58
+ end
59
+ ```
60
+
61
+ Also, you can configurate what associations you want to see in YourModel page in admin panel *support only for [tramway-admin](https://rubygems.org/gems/tramway-admin) gem*
62
+
63
+ *app/decorators/your_model_decorator.rb*
64
+ ```ruby
65
+ class YourModelDecorator < Tramway::Core::ApplicationDecorator
66
+ class << self
67
+ def show_associations
68
+ [ :some_model, :another_model, :another_one_model ]
69
+ end
70
+ end
71
+ end
72
+ ```
73
+
74
+ ### Delegating attributes
75
+
76
+ *app/decorators/your_model_decorator.rb*
77
+ ```ruby
78
+ class YourModelDecorator < Tramway::Core::ApplicationDecorator
79
+ delegate_attributes :title, :something_else, :another_atttribute
80
+ end
81
+ ```
82
+
37
83
  ### Helper methods
38
84
 
39
85
  #### date_view
@@ -157,8 +203,10 @@ Tramway::Admin.set_singleton_models Organization, project: :organization # now y
157
203
  * models - часто используемые в моделях слова
158
204
  * state_machines - локализация состояний
159
205
 
160
- ## Contributing
161
- Contribution directions go here.
206
+ ## Contributors
207
+
208
+ * [Pavel Kalashnikov](https://github.com/kalashnikovisme)
209
+ * [moshinaan](https://github.com/moshinaan)
162
210
 
163
211
  ## License
164
212
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -1,18 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Tramway
4
- module Core
5
- class ApplicationController < ActionController::Base
6
- before_action :application
7
- before_action :load_extensions
3
+ class Tramway::Core::ApplicationController < ActionController::Base
4
+ before_action :application
5
+ before_action :load_extensions
8
6
 
9
- def application
10
- @application = ::Tramway::Core.application_object
11
- end
7
+ def application
8
+ @application = ::Tramway::Core.application_object
9
+ end
12
10
 
13
- def load_extensions
14
- ::Tramway::Extensions.load if defined? ::Tramway::Extensions
15
- end
16
- end
11
+ def load_extensions
12
+ ::Tramway::Extensions.load if defined? ::Tramway::Extensions
17
13
  end
18
14
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'tramway/error'
4
+ require 'tramway/helpers/class_name_helpers'
4
5
 
5
6
  class Tramway::Core::ApplicationDecorator
6
7
  include ActionView::Helpers
@@ -8,6 +9,8 @@ class Tramway::Core::ApplicationDecorator
8
9
  include ::FontAwesome5::Rails::IconHelper
9
10
  include ::Tramway::Core::CopyToClipboardHelper
10
11
  include ::Tramway::Core::Associations::ObjectHelper
12
+ include ::Tramway::Core::Attributes::ViewHelper
13
+ include ::Tramway::ClassNameHelpers
11
14
 
12
15
  def initialize(object)
13
16
  @object = object
@@ -18,12 +21,18 @@ class Tramway::Core::ApplicationDecorator
18
21
  end
19
22
 
20
23
  def title
21
- error = Tramway::Error.new(plugin: :core, method: :title, message: "Please, implement `title` method in a #{self.class} or #{object.class}")
22
- raise error.message
24
+ Tramway::Error.raise_error(
25
+ :tramway, :core, :application_decorator, :title, :please_implement_title,
26
+ class_name: self.class, object_class: object.class
27
+ )
23
28
  end
24
29
 
30
+ delegate :id, to: :object
31
+ delegate :human_state_name, to: :object
32
+
25
33
  class << self
26
34
  include ::Tramway::Core::Associations::ClassHelper
35
+ include ::Tramway::Core::Delegating::ClassHelper
27
36
 
28
37
  def collections
29
38
  [:all]
@@ -61,19 +70,11 @@ class Tramway::Core::ApplicationDecorator
61
70
  end
62
71
  end
63
72
 
64
- delegate :id, to: :object
65
- delegate :human_state_name, to: :object
66
-
67
73
  def link
68
74
  if object.try :file
69
75
  object.file.url
70
76
  else
71
- error = Tramway::Error.new(
72
- plugin: :core,
73
- method: :link,
74
- message: "Method `link` uses `file` attribute of the decorated object. If decorated object doesn't contain `file`, you shouldn't use `link` method."
75
- )
76
- raise error.message
77
+ Tramway::Error.raise_error :tramway, :core, :application_decorator, :link, :method_link_uses_file_attribute
77
78
  end
78
79
  end
79
80
 
@@ -96,25 +97,12 @@ class Tramway::Core::ApplicationDecorator
96
97
  def attributes
97
98
  object.attributes.reduce({}) do |hash, attribute|
98
99
  if attribute[0].in? RESERVED_WORDS
99
- error = Tramway::Error.new(
100
- plugin: :core,
101
- method: :attributes,
102
- message: "Method `#{attribute[0]}` is reserved word. Please, create or delegate method in #{self.class.name} with another name."
100
+ Tramway::Error.raise_error(
101
+ :tramway, :core, :application_decorator, :attributes, :method_is_reserved_word,
102
+ attribute_name: attribute[0], class_name: self.class.name
103
103
  )
104
- raise error.message
105
- end
106
- value = try(attribute[0]) ? send(attribute[0]) : object.send(attribute[0])
107
- if attribute[0].to_s.in? object.class.state_machines.keys.map(&:to_s)
108
- hash.merge! attribute[0] => state_machine_view(object, attribute[0])
109
- elsif value.class.in? [ActiveSupport::TimeWithZone, DateTime, Time]
110
- hash.merge! attribute[0] => datetime_view(attribute[1])
111
- elsif value.class.superclass == ApplicationUploader
112
- hash.merge! attribute[0] => image_view(object.send(attribute[0]))
113
- elsif value.is_a? Enumerize::Value
114
- hash.merge! attribute[0] => enumerize_view(value)
115
- else
116
- hash.merge! attribute[0] => value
117
104
  end
105
+ hash.merge! attribute[0] => build_viewable_value(object, attribute)
118
106
  end
119
107
  end
120
108
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tramway::Core::Associations::ClassHelper
2
4
  def decorate_association(association_name, decorator: nil, as: nil, state_machines: [])
3
5
  @@decorated_associations ||= []
@@ -14,27 +16,25 @@ module Tramway::Core::Associations::ClassHelper
14
16
  end
15
17
 
16
18
  define_method "add_#{association_name}_form" do
17
- "Admin::#{object.class.to_s.pluralize}::Add#{association_name.to_s.camelize.singularize}Form".constantize.new object
19
+ add_association_form_class_name(object, association_name).new object
18
20
  end
19
21
  end
20
22
 
23
+ def decorate_associations(*association_names)
24
+ association_names.each do |association_name|
25
+ decorate_association association_name
26
+ end
27
+ end
21
28
 
22
29
  def define_main_association_method(association_name, decorator)
23
30
  define_method association_name do
24
31
  association = object.class.reflect_on_association(association_name)
25
- if association.nil?
26
- error = Tramway::Error.new(plugin: :core, method: :decorate_association, message: "Model #{object.class} does not have association named `#{association_name}`")
27
- raise error.message
28
- end
29
- decorator_class_name = decorator || "#{class_name(association).to_s.singularize}Decorator".constantize
30
- if association.class.in? [ ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection ]
31
- return object.send(association_name).active.map do |association_object|
32
- decorator_class_name.decorate association_object
33
- end
34
- end
35
- if association.class == ActiveRecord::Reflection::BelongsToReflection
36
- return decorator_class_name.decorate object.send association_name
32
+ check_association object, association_name, association
33
+ decorator_class_name = decorator || decorator_class_name(class_name(association))
34
+ if association_type(association).in? %i[has_many has_and_belongs_to_many]
35
+ return associations_collection(object, association_name, decorator_class_name)
37
36
  end
37
+ return decorator_class_name.decorate object.send association_name if association_type(association) == :belongs_to
38
38
  end
39
39
  end
40
40
  end
@@ -1,13 +1,41 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tramway::Core::Associations::ObjectHelper
2
4
  def class_name(association)
3
5
  if association.polymorphic?
4
- object.send(association_name).class
6
+ object.send(association.name).class
5
7
  else
6
8
  unless association.options[:class_name]
7
- error = Tramway::Error.new(plugin: :core, method: :decorate_association, message: "Please, specify `#{association_name}` association class_name in #{object.class} model. For example: `has_many :#{association_name}, class_name: '#{association_name.to_s.singularize.camelize}'`")
8
- raise error.message
9
+ Tramway::Error.raise_error(
10
+ :tramway, :core, :associations, :object_helper, :please_specify_association_name,
11
+ association_name: association.name, object_class: object.class,
12
+ association_class_name: association.name.to_s.singularize.camelize
13
+ )
9
14
  end
10
15
  association.options[:class_name]
11
16
  end
12
17
  end
18
+
19
+ def check_association(object, association_name, association)
20
+ return unless association.nil?
21
+
22
+ Tramway::Error.raise_error(
23
+ :tramway, :core, :associations, :class_helper, :model_does_not_have_association,
24
+ object_class: object.class, association_name: association_name
25
+ )
26
+ end
27
+
28
+ def association_type(association)
29
+ association.class.to_s.split('::').last.sub(/Reflection$/, '').underscore.to_sym
30
+ end
31
+
32
+ def associations_collection(object, association_name, decorator_class_name)
33
+ object.send(association_name).active.map do |association_object|
34
+ decorator_class_name.decorate association_object
35
+ end
36
+ end
37
+
38
+ def add_association_form_class_name(object, association_name)
39
+ "Admin::#{object.class.to_s.pluralize}::Add#{association_name.to_s.camelize.singularize}Form".constantize
40
+ end
13
41
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::Attributes::ViewHelper
4
+ def build_viewable_value(object, attribute)
5
+ value = try(attribute[0]) ? send(attribute[0]) : object.send(attribute[0])
6
+ return state_machine_view(object, attribute[0]) if state_machine? object, attribute[0]
7
+
8
+ view_by_value object, value, attribute
9
+ end
10
+
11
+ def state_machine?(object, attribute_name)
12
+ attribute_name.to_s.in? object.class.state_machines.keys.map(&:to_s)
13
+ end
14
+
15
+ def view_by_value(object, value, attribute)
16
+ if value.class.in? [ActiveSupport::TimeWithZone, DateTime, Time]
17
+ datetime_view(attribute[1])
18
+ elsif value.class.superclass == ApplicationUploader
19
+ image_view(object.send(attribute[0]))
20
+ elsif value.is_a? Enumerize::Value
21
+ enumerize_view(value)
22
+ else
23
+ value
24
+ end
25
+ end
26
+ end
@@ -13,37 +13,58 @@ module Tramway::Core::Concerns::AttributesDecoratorHelper
13
13
  object.send "human_#{attribute_name}_name"
14
14
  end
15
15
 
16
+ BASE64_REGEXP = %r{^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|
17
+ (?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$}x.freeze
18
+
16
19
  def image_view(original, thumb: nil, filename: nil)
17
- if original.present?
18
- thumb ||= original.is_a?(CarrierWave::Uploader::Base) ? original.small : nil
19
- filename ||= original.is_a?(CarrierWave::Uploader::Base) ? original.path&.split('/')&.last : nil
20
- src_thumb = if thumb&.is_a?(CarrierWave::Uploader::Base)
21
- thumb.url
22
- elsif thumb&.match(%r{^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$})
23
- "data:image/jpeg;base64,#{thumb}"
24
- else
25
- thumb
26
- end
27
- src_original = if original.is_a?(CarrierWave::Uploader::Base)
28
- original.url
29
- elsif original.match(%r{^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$})
30
- "data:image/jpeg;base64,#{original}"
31
- else
32
- original
33
- end
34
- content_tag(:div) do
35
- begin
36
- concat image_tag src_thumb || src_original
37
- rescue NoMethodError => e
38
- error = Tramway::Error.new plugin: :core, method: :image_view, message: "You should mount PhotoUploader to your model. Just add `mount_uploader \#{attribute_name}, PhotoUploader` to your model. #{e.message}"
39
- raise error.message
40
- end
41
- concat link_to(fa_icon(:download), src_original, class: 'btn btn-success', download: filename) if filename
42
- end
20
+ return unless original.present?
21
+
22
+ filename ||= build_filename(original)
23
+ content_tag(:div) do
24
+ build_div_content src_original(original), src_thumb(original, thumb), filename || build_filename(original)
43
25
  end
44
26
  end
45
27
 
46
28
  def enumerize_view(value)
47
29
  value.text
48
30
  end
31
+
32
+ private
33
+
34
+ def src_thumb(original, thumb)
35
+ thumb ||= original.is_a?(CarrierWave::Uploader::Base) ? original.small : nil
36
+ if thumb&.is_a?(CarrierWave::Uploader::Base)
37
+ thumb.url
38
+ elsif thumb&.match(BASE64_REGEXP)
39
+ "data:image/jpeg;base64,#{thumb}"
40
+ else
41
+ thumb
42
+ end
43
+ end
44
+
45
+ def src_original(original)
46
+ if original.is_a?(CarrierWave::Uploader::Base)
47
+ original.url
48
+ elsif original.match(BASE64_REGEXP)
49
+ "data:image/jpeg;base64,#{original}"
50
+ else
51
+ original
52
+ end
53
+ end
54
+
55
+ def build_filename(original)
56
+ original.is_a?(CarrierWave::Uploader::Base) ? original.path&.split('/')&.last : nil
57
+ end
58
+
59
+ def build_div_content(original, thumb, filename)
60
+ begin
61
+ concat image_tag src_thumb(original, thumb) || src_original(original)
62
+ rescue NoMethodError => e
63
+ Tramway::Error.raise_error(
64
+ :tramway, :core, :concerns, :attributes_decorator_helper, :you_should_mount_photo_uploader,
65
+ message: e.message, attribute_name: attribute_name
66
+ )
67
+ end
68
+ concat link_to(fa_icon(:download), src_original(original), class: 'btn btn-success', download: filename) if filename
69
+ end
49
70
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::Delegating::ClassHelper
4
+ def delegate_attributes(*attributes)
5
+ attributes.each do |attr|
6
+ delegate attr, to: :object
7
+ end
8
+ end
9
+ end
@@ -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