tramway-core 1.17.2.1 → 1.17.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.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/app/controllers/tramway/core/application_controller.rb +12 -12
- data/app/decorators/tramway/core/application_decorator.rb +12 -26
- data/app/decorators/tramway/core/associations/class_helper.rb +7 -13
- data/app/decorators/tramway/core/associations/object_helper.rb +28 -2
- data/app/decorators/tramway/core/attributes/view_helper.rb +26 -0
- data/app/decorators/tramway/core/concerns/attributes_decorator_helper.rb +47 -26
- data/app/decorators/tramway/core/delegating/class_helper.rb +2 -0
- data/app/forms/tramway/core/application_form.rb +96 -145
- data/app/forms/tramway/core/application_forms/association_object_helpers.rb +27 -0
- data/app/forms/tramway/core/application_forms/constant_class_actions.rb +7 -0
- data/app/forms/tramway/core/application_forms/constant_object_actions.rb +20 -0
- data/app/forms/tramway/core/application_forms/properties_object_helper.rb +23 -0
- data/app/forms/tramway/core/extendable_form.rb +3 -70
- data/app/forms/tramway/core/extendable_forms_helpers/class_builder.rb +34 -0
- data/app/forms/tramway/core/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
- data/app/forms/tramway/core/extendable_forms_helpers/more_properties_helper.rb +27 -0
- data/app/forms/tramway/core/extendable_forms_helpers/properties_helper.rb +16 -0
- data/app/forms/tramway/core/extendable_forms_helpers/submit/class_helpers.rb +18 -0
- data/app/forms/tramway/core/extendable_forms_helpers/submit/object_helpers.rb +7 -0
- data/app/forms/tramway/core/extendable_forms_helpers/validators.rb +40 -0
- data/app/helpers/tramway/core/application_helper.rb +2 -0
- data/app/helpers/tramway/core/copy_to_clipboard_helper.rb +6 -10
- data/app/helpers/tramway/core/inputs_helper.rb +93 -0
- data/app/helpers/tramway/core/title_helper.rb +17 -22
- data/app/models/tramway/core/application_record.rb +38 -40
- data/app/uploaders/image_defaults.rb +2 -1
- data/app/uploaders/photo_uploader.rb +8 -8
- data/app/views/tramway/core/shared/_input.html.haml +26 -0
- data/config/initializers/plurals.rb +2 -2
- data/lib/tramway/collection.rb +4 -6
- data/lib/tramway/collections.rb +4 -0
- data/lib/tramway/collections/helper.rb +15 -14
- data/lib/tramway/core.rb +22 -22
- data/lib/tramway/core/engine.rb +4 -8
- data/lib/tramway/core/generators.rb +6 -0
- data/lib/tramway/core/generators/install_generator.rb +17 -17
- data/lib/tramway/core/version.rb +1 -1
- data/lib/tramway/error.rb +12 -1
- data/lib/yaml/errors.yml +35 -0
- metadata +22 -3
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ApplicationForms::AssociationObjectHelpers
|
4
|
+
def define_association_method(association, class_name)
|
5
|
+
if class_name.is_a? Array
|
6
|
+
define_polymorphic_association association, class_name
|
7
|
+
else
|
8
|
+
self.class.send(:define_method, "#{association}=") do |value|
|
9
|
+
super class_name.find value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_polymorphic_association(association, _class_name)
|
15
|
+
self.class.send(:define_method, "#{association}=") do |value|
|
16
|
+
association_class = value.split('_')[0..-2].join('_').camelize
|
17
|
+
association_class = association_class.constantize if association_class.is_a? String
|
18
|
+
if association_class.nil?
|
19
|
+
Tramway::Error.raise_error :tramway, :core, :application_form, :initialize, :polymorphic_class_is_nil,
|
20
|
+
association_name: association
|
21
|
+
else
|
22
|
+
super association_class.find value.split('_')[-1]
|
23
|
+
send "#{association}_type=", association_class.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
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({}) do |hash, property|
|
12
|
+
value = if model.respond_to? :values
|
13
|
+
model.values[property.first.to_s]
|
14
|
+
else
|
15
|
+
model.send(property.first.to_s)
|
16
|
+
end
|
17
|
+
hash.merge! property.first => value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
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
|
-
|
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) && model.errors.empty?
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::InputsHelper
|
4
|
+
def association_params(form_object:, property:, value:, object:, options: {})
|
5
|
+
full_class_name_association = form_object.class.full_class_name_association(property)
|
6
|
+
unless full_class_name_association
|
7
|
+
raise "It seems you've defined association attributes with `property` method. Please, use `association` method. `association :#{property}`"
|
8
|
+
end
|
9
|
+
if full_class_name_association.is_a? Array
|
10
|
+
raise "It seems you've used `association` input type in the Form. Please, use `polymorphic_association` type. `#{property}: :polymorphic_association`"
|
11
|
+
end
|
12
|
+
|
13
|
+
{
|
14
|
+
label: false,
|
15
|
+
input_html: {
|
16
|
+
name: "#{object}[#{property}]",
|
17
|
+
id: "#{object}_#{property}",
|
18
|
+
value: (form_object.send(property) || form_object.model.send("#{property}_id") || value)
|
19
|
+
},
|
20
|
+
selected: (form_object.model.send("#{property}_id") || value),
|
21
|
+
collection: full_class_name_association.active.map do |obj|
|
22
|
+
decorator_class(full_class_name_association).decorate obj
|
23
|
+
end.sort_by(&:name)
|
24
|
+
}.merge options
|
25
|
+
end
|
26
|
+
|
27
|
+
def polymorphic_association_params(object:, form_object:, property:, value:, options: {})
|
28
|
+
full_class_names = form_object.model.class.send("#{property}_type").values.map &:constantize
|
29
|
+
collection = full_class_names.map do |class_name|
|
30
|
+
class_name.active.map do |obj|
|
31
|
+
decorator_class(class_name).decorate obj
|
32
|
+
end
|
33
|
+
end.flatten.sort_by { |obj| obj.name.to_s }
|
34
|
+
builded_value = if form_object.send(property).present?
|
35
|
+
"#{form_object.send(property).class.to_s.underscore}_#{form_object.send(property).id}"
|
36
|
+
else
|
37
|
+
"#{value[:type]&.underscore}_#{value[:id]}"
|
38
|
+
end
|
39
|
+
{
|
40
|
+
as: :select,
|
41
|
+
label: false,
|
42
|
+
input_html: {
|
43
|
+
name: "#{object}[#{property}]",
|
44
|
+
id: "#{object}_#{property}",
|
45
|
+
value: builded_value
|
46
|
+
},
|
47
|
+
selected: builded_value,
|
48
|
+
collection: collection,
|
49
|
+
label_method: lambda do |obj|
|
50
|
+
"#{obj.class.model_name.human} | #{obj.name}"
|
51
|
+
end,
|
52
|
+
value_method: lambda do |obj|
|
53
|
+
"#{obj.class.to_s.underscore.sub(/_decorator$/, '')}_#{obj.id}"
|
54
|
+
end
|
55
|
+
}.merge options
|
56
|
+
end
|
57
|
+
|
58
|
+
def value_from_params(model_class:, property:, type:)
|
59
|
+
case type
|
60
|
+
when :polymorphic_association, 'polymorphic_association'
|
61
|
+
{
|
62
|
+
id: params.dig(model_class.to_s.underscore, property.to_s),
|
63
|
+
type: params.dig(model_class.to_s.underscore, "#{property}_type")
|
64
|
+
}
|
65
|
+
else
|
66
|
+
params.dig(model_class.to_s.underscore, property.to_s)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_params(property:, object:, form_object:, value:, options: {})
|
71
|
+
{
|
72
|
+
label: false,
|
73
|
+
input_html: {
|
74
|
+
name: "#{object}[#{property}]",
|
75
|
+
id: "#{object}_#{property}",
|
76
|
+
value: (form_object.send(property) || form_object.model.send(property) || value)
|
77
|
+
},
|
78
|
+
selected: (form_object.model.send(property) || value)
|
79
|
+
}.merge options
|
80
|
+
end
|
81
|
+
|
82
|
+
def else_params(property:, object:, type:, form_object:, value:, options: {})
|
83
|
+
{
|
84
|
+
as: type,
|
85
|
+
label: false,
|
86
|
+
input_html: {
|
87
|
+
name: "#{object}[#{property}]",
|
88
|
+
id: "#{object}_#{property}",
|
89
|
+
value: (form_object.send(property) || form_object.model.send(property) || value)
|
90
|
+
}
|
91
|
+
}.merge options
|
92
|
+
end
|
93
|
+
end
|