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
@@ -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
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::ClassBuilder
4
+ def build_form_class(name, simple_properties, more_properties)
5
+ Object.const_set(name, Class.new(::Tramway::Core::ApplicationForm) do
6
+ properties(*simple_properties.keys) if simple_properties.keys.any?
7
+
8
+ include Tramway::Core::ExtendableFormsHelpers::Submit::ObjectHelpers
9
+ include Tramway::Core::ExtendableFormsHelpers::Validators
10
+ extend Tramway::Core::ExtendableFormsHelpers::Submit::ClassHelpers
11
+ extend Tramway::Core::ExtendableFormsHelpers::PropertiesHelper
12
+ extend Tramway::Core::ExtendableFormsHelpers::MorePropertiesHelper
13
+ extend Tramway::Core::ExtendableFormsHelpers::IgnoredPropertiesHelper
14
+
15
+ define_submit_method simple_properties, more_properties
16
+ define_properties_method simple_properties, more_properties
17
+ define_ignored_properties_method
18
+
19
+ more_properties.each do |property|
20
+ define_property_method property[0]
21
+
22
+ case property[1][:object].field_type
23
+ when 'file'
24
+ field = property[1][:object]
25
+ define_file_property_assignment_method property field
26
+ else
27
+ next unless property[1][:validates].present?
28
+
29
+ define_assignment_method property
30
+ end
31
+ end
32
+ end)
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::IgnoredPropertiesHelper
4
+ def define_ignored_properties_method
5
+ define_method :jsonb_ignored_properties do |properties|
6
+ properties.map do |property|
7
+ property[0].to_s if property[1][:object].field_type == 'file'
8
+ end.compact
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::MorePropertiesHelper
4
+ def define_property_method(property_name)
5
+ define_method property_name do
6
+ model.values[property_name] if model.values
7
+ end
8
+ end
9
+
10
+ def define_assignment_method(property)
11
+ define_method "#{property[0]}=" do |value|
12
+ property[1][:validates].each do |pair|
13
+ make_validates property[0], pair, value
14
+ end
15
+ end
16
+ end
17
+
18
+ def define_file_property_assignment_method(property, field)
19
+ define_method "#{property[0]}=" do |value|
20
+ file_instance = property[1][:association_model].find_or_create_by(
21
+ "#{model.class.name.underscore}_id" => model.id, "#{field.class.name.underscore}_id" => field.id
22
+ )
23
+ file_instance.file = value
24
+ file_instance.save!
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::PropertiesHelper
4
+ def define_properties_method(simple_properties, more_properties)
5
+ define_method 'properties' do
6
+ hash = simple_properties.each_with_object({}) do |property, h|
7
+ h.merge! property[0] => property[1] unless model.class.state_machines.keys.include?(property[0])
8
+ end
9
+ more_properties.reduce(hash) do |h, property|
10
+ h.merge! property[0] => {
11
+ extended_form_property: property[1][:object]
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::Submit::ClassHelpers
4
+ def define_submit_method(simple_properties, more_properties)
5
+ define_method 'submit' do |params|
6
+ model.values ||= {}
7
+ extended_params = extended(simple_properties, more_properties, params)
8
+ params.each do |key, value|
9
+ method_name = "#{key}="
10
+ send method_name, value if respond_to?(method_name)
11
+ end
12
+ model.values = extended_params.reduce(model.values) do |hash, pair|
13
+ hash.merge! pair[0] => pair[1]
14
+ end
15
+ super(params) && model.errors.empty?
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::Submit::ObjectHelpers
4
+ def extended(simple_properties, more_properties, params)
5
+ params.except(*simple_properties.keys).except(*jsonb_ignored_properties(more_properties)).permit!.to_h
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Core::ExtendableFormsHelpers::Validators
4
+ def make_validates(property_name, validation, value)
5
+ case validation[0].to_s
6
+ when 'presence'
7
+ presence_validator property_name, validation, value
8
+ when 'inclusion'
9
+ inclusion_validator property_name, validation, value
10
+ end
11
+ end
12
+
13
+ def presence_validator(property_name, validation, value)
14
+ validator_object = PresenceValidator.new(attributes: :not_blank)
15
+ return if validation[1] == 'false'
16
+ return if validation[1] == 'true' && validator_object.send(:valid?, value)
17
+
18
+ model.errors.add(
19
+ property_name,
20
+ I18n.t(
21
+ "activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{validation[0]}",
22
+ value: value
23
+ )
24
+ )
25
+ end
26
+
27
+ def inclusion_validator(property_name, validation, value)
28
+ in_array = validation[1][:in]
29
+
30
+ return if value.in? in_array
31
+
32
+ model.errors.add(
33
+ property_name,
34
+ I18n.t(
35
+ "activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{validation[0]}",
36
+ value: value
37
+ )
38
+ )
39
+ end
40
+ end
@@ -1,15 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Tramway
4
- module Core
5
- module CopyToClipboardHelper
6
- def copy_to_clipboard(id)
7
- button_tag class: 'btn btn-info clipboard-btn',
8
- data: { clipboard_action: 'copy', clipboard_target: "##{id}" },
9
- style: 'margin-left: 15px' do
10
- fa_icon 'copy'
11
- end
12
- end
3
+ module Tramway::Core::CopyToClipboardHelper
4
+ def copy_to_clipboard(id)
5
+ button_tag class: 'btn btn-info clipboard-btn',
6
+ data: { clipboard_action: 'copy', clipboard_target: "##{id}" },
7
+ style: 'margin-left: 15px' do
8
+ fa_icon 'copy'
13
9
  end
14
10
  end
15
11
  end
@@ -1,29 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Tramway
4
- module Core
5
- module TitleHelper
6
- def title(page_title = default_title)
7
- if @application.present?
8
- title_text = "#{page_title} | #{@application.try(:title) || @application.public_name}"
9
- content_for(:title) { title_text }
10
- else
11
- error = Tramway::Error.new(plugin: :core, method: :title, message: 'You should set Tramway::Core::Application class using `::Tramway::Core.initialize_application model_class: #{model_class_name}` in config/initializers/tramway.rb OR maybe you don\'t have any records of application model')
12
- raise error.message
13
- end
14
- end
3
+ module Tramway::Core::TitleHelper
4
+ def title(page_title = default_title)
5
+ if @application.present?
6
+ title_text = "#{page_title} | #{@application.try(:title) || @application.public_name}"
7
+ content_for(:title) { title_text }
8
+ else
9
+ Tramway::Error.raise_error(:tramway, :core, :title_helper, :title, :you_should_set_tramway_core_application)
10
+ end
11
+ end
15
12
 
16
- def default_title
17
- t('.title')
18
- end
13
+ def default_title
14
+ t('.title')
15
+ end
19
16
 
20
- def page_title(action, model_name)
21
- if I18n.locale == :ru
22
- t("helpers.actions.#{action}") + ' ' + genitive(model_name)
23
- else
24
- t("helpers.actions.#{action}") + ' ' + model_name.model_name.human.downcase
25
- end
26
- end
17
+ def page_title(action, model_name)
18
+ if I18n.locale == :ru
19
+ t("helpers.actions.#{action}") + ' ' + genitive(model_name)
20
+ else
21
+ t("helpers.actions.#{action}") + ' ' + model_name.model_name.human.downcase
27
22
  end
28
23
  end
29
24
  end
@@ -2,52 +2,50 @@
2
2
 
3
3
  require 'carrierwave/orm/activerecord' if defined?(CarrierWave::Mount)
4
4
 
5
- module Tramway
6
- module Core
7
- class ApplicationRecord < ActiveRecord::Base
8
- self.abstract_class = true
9
- audited
10
- extend ::Enumerize
11
-
12
- state_machine :state, initial: :active do
13
- state :active
14
- state :removed
15
-
16
- event :remove do
17
- transition active: :remove
18
- end
19
- end
5
+ class Tramway::Core::ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+ audited
8
+ extend ::Enumerize
20
9
 
21
- scope :active, -> { where state: :active }
22
- scope :created_by_user, ->(user_id) { joins(:audits).where('audits.action = \'create\' AND audits.user_id = ?', user_id) }
23
- scope :admin_scope, ->(_arg) { all }
10
+ state_machine :state, initial: :active do
11
+ state :active
12
+ state :removed
24
13
 
25
- include ::PgSearch::Model
14
+ event :remove do
15
+ transition active: :remove
16
+ end
17
+ end
26
18
 
27
- def creator
28
- audits.where(action: :create).first.user
29
- end
19
+ scope :active, -> { where state: :active }
20
+ scope :created_by_user, lambda { |user_id|
21
+ joins(:audits).where('audits.action = \'create\' AND audits.user_id = ?', user_id)
22
+ }
23
+ scope :admin_scope, ->(_arg) { all }
30
24
 
31
- # FIXME: detect inhertited locales
32
- class << self
33
- def human_attribute_name(attribute_name, *_args)
34
- excepted_attributes = %w[created_at updated_at state]
35
- if attribute_name.to_s.in? excepted_attributes
36
- I18n.t "activerecord.attributes.tramway/core/application_record.#{attribute_name}"
37
- else
38
- super attribute_name
39
- end
40
- end
41
-
42
- def search_by(*attributes, **associations)
43
- pg_search_scope :full_text_search, against: attributes, associated_against: associations
44
- end
45
- end
25
+ include ::PgSearch::Model
46
26
 
47
- # FIXME: detect inhertited locales
48
- def human_state_name
49
- I18n.t "activerecord.state_machines.tramway/core/application_record.state.states.#{state}"
27
+ def creator
28
+ audits.where(action: :create).first.user
29
+ end
30
+
31
+ # FIXME: detect inhertited locales
32
+ class << self
33
+ def human_attribute_name(attribute_name, *_args)
34
+ excepted_attributes = %w[created_at updated_at state]
35
+ if attribute_name.to_s.in? excepted_attributes
36
+ I18n.t "activerecord.attributes.tramway/core/application_record.#{attribute_name}"
37
+ else
38
+ super attribute_name
50
39
  end
51
40
  end
41
+
42
+ def search_by(*attributes, **associations)
43
+ pg_search_scope :full_text_search, against: attributes, associated_against: associations
44
+ end
45
+ end
46
+
47
+ # FIXME: detect inhertited locales
48
+ def human_state_name
49
+ I18n.t "activerecord.state_machines.tramway/core/application_record.state.states.#{state}"
52
50
  end
53
51
  end