wallaby-core 0.1.0
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/app/controllers/wallaby/application_controller.rb +84 -0
- data/app/controllers/wallaby/resources_controller.rb +381 -0
- data/app/controllers/wallaby/secure_controller.rb +81 -0
- data/app/security/ability.rb +13 -0
- data/config/locales/wallaby.en.yml +140 -0
- data/config/locales/wallaby_class.en.yml +30 -0
- data/config/routes.rb +39 -0
- data/lib/adaptors/wallaby/custom.rb +7 -0
- data/lib/adaptors/wallaby/custom/default_provider.rb +9 -0
- data/lib/adaptors/wallaby/custom/model_decorator.rb +71 -0
- data/lib/adaptors/wallaby/custom/model_finder.rb +13 -0
- data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +14 -0
- data/lib/adaptors/wallaby/custom/model_service_provider.rb +48 -0
- data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +72 -0
- data/lib/authorizers/wallaby/default_authorization_provider.rb +58 -0
- data/lib/authorizers/wallaby/model_authorizer.rb +100 -0
- data/lib/authorizers/wallaby/pundit_authorization_provider.rb +89 -0
- data/lib/concerns/wallaby/authorizable.rb +103 -0
- data/lib/concerns/wallaby/baseable.rb +36 -0
- data/lib/concerns/wallaby/decoratable.rb +101 -0
- data/lib/concerns/wallaby/defaultable.rb +38 -0
- data/lib/concerns/wallaby/engineable.rb +61 -0
- data/lib/concerns/wallaby/fieldable.rb +78 -0
- data/lib/concerns/wallaby/paginatable.rb +72 -0
- data/lib/concerns/wallaby/rails_overridden_methods.rb +42 -0
- data/lib/concerns/wallaby/resourcable.rb +149 -0
- data/lib/concerns/wallaby/servicable.rb +68 -0
- data/lib/concerns/wallaby/shared_helpers.rb +22 -0
- data/lib/concerns/wallaby/themeable.rb +40 -0
- data/lib/decorators/wallaby/resource_decorator.rb +189 -0
- data/lib/errors/wallaby/cell_handling.rb +6 -0
- data/lib/errors/wallaby/forbidden.rb +6 -0
- data/lib/errors/wallaby/general_error.rb +6 -0
- data/lib/errors/wallaby/invalid_error.rb +6 -0
- data/lib/errors/wallaby/model_not_found.rb +11 -0
- data/lib/errors/wallaby/not_authenticated.rb +6 -0
- data/lib/errors/wallaby/not_found.rb +6 -0
- data/lib/errors/wallaby/not_implemented.rb +6 -0
- data/lib/errors/wallaby/resource_not_found.rb +11 -0
- data/lib/errors/wallaby/unprocessable_entity.rb +6 -0
- data/lib/forms/wallaby/form_builder.rb +60 -0
- data/lib/helpers/wallaby/application_helper.rb +79 -0
- data/lib/helpers/wallaby/base_helper.rb +65 -0
- data/lib/helpers/wallaby/configuration_helper.rb +18 -0
- data/lib/helpers/wallaby/form_helper.rb +62 -0
- data/lib/helpers/wallaby/index_helper.rb +84 -0
- data/lib/helpers/wallaby/links_helper.rb +213 -0
- data/lib/helpers/wallaby/resources_helper.rb +52 -0
- data/lib/helpers/wallaby/secure_helper.rb +54 -0
- data/lib/helpers/wallaby/styling_helper.rb +82 -0
- data/lib/interfaces/wallaby/mode.rb +72 -0
- data/lib/interfaces/wallaby/model_authorization_provider.rb +99 -0
- data/lib/interfaces/wallaby/model_decorator.rb +168 -0
- data/lib/interfaces/wallaby/model_finder.rb +12 -0
- data/lib/interfaces/wallaby/model_pagination_provider.rb +107 -0
- data/lib/interfaces/wallaby/model_service_provider.rb +84 -0
- data/lib/paginators/wallaby/model_paginator.rb +115 -0
- data/lib/paginators/wallaby/resource_paginator.rb +12 -0
- data/lib/parsers/wallaby/parser.rb +34 -0
- data/lib/renderers/wallaby/cell.rb +137 -0
- data/lib/renderers/wallaby/cell_resolver.rb +89 -0
- data/lib/renderers/wallaby/custom_lookup_context.rb +64 -0
- data/lib/renderers/wallaby/custom_partial_renderer.rb +33 -0
- data/lib/renderers/wallaby/custom_renderer.rb +16 -0
- data/lib/responders/wallaby/json_api_responder.rb +101 -0
- data/lib/responders/wallaby/resources_responder.rb +28 -0
- data/lib/routes/wallaby/resources_router.rb +72 -0
- data/lib/servicers/wallaby/model_servicer.rb +154 -0
- data/lib/services/wallaby/engine_name_finder.rb +22 -0
- data/lib/services/wallaby/engine_url_for.rb +46 -0
- data/lib/services/wallaby/link_options_normalizer.rb +19 -0
- data/lib/services/wallaby/map/mode_mapper.rb +27 -0
- data/lib/services/wallaby/map/model_class_collector.rb +49 -0
- data/lib/services/wallaby/map/model_class_mapper.rb +38 -0
- data/lib/services/wallaby/prefixes_builder.rb +66 -0
- data/lib/services/wallaby/sorting/hash_builder.rb +19 -0
- data/lib/services/wallaby/sorting/link_builder.rb +69 -0
- data/lib/services/wallaby/sorting/next_builder.rb +63 -0
- data/lib/services/wallaby/sorting/single_builder.rb +20 -0
- data/lib/services/wallaby/type_renderer.rb +50 -0
- data/lib/support/action_dispatch/routing/mapper.rb +75 -0
- data/lib/tree/wallaby/node.rb +25 -0
- data/lib/utils/wallaby/cell_utils.rb +34 -0
- data/lib/utils/wallaby/field_utils.rb +43 -0
- data/lib/utils/wallaby/filter_utils.rb +20 -0
- data/lib/utils/wallaby/model_utils.rb +51 -0
- data/lib/utils/wallaby/module_utils.rb +46 -0
- data/lib/utils/wallaby/params_utils.rb +14 -0
- data/lib/utils/wallaby/preload_utils.rb +44 -0
- data/lib/utils/wallaby/test_utils.rb +34 -0
- data/lib/utils/wallaby/utils.rb +27 -0
- data/lib/wallaby/configuration.rb +103 -0
- data/lib/wallaby/configuration/features.rb +24 -0
- data/lib/wallaby/configuration/mapping.rb +140 -0
- data/lib/wallaby/configuration/metadata.rb +23 -0
- data/lib/wallaby/configuration/models.rb +46 -0
- data/lib/wallaby/configuration/pagination.rb +30 -0
- data/lib/wallaby/configuration/security.rb +98 -0
- data/lib/wallaby/configuration/sorting.rb +28 -0
- data/lib/wallaby/constants.rb +45 -0
- data/lib/wallaby/core.rb +117 -0
- data/lib/wallaby/core/version.rb +7 -0
- data/lib/wallaby/engine.rb +43 -0
- data/lib/wallaby/map.rb +170 -0
- metadata +222 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Servicer related attributes
|
|
5
|
+
module Servicable
|
|
6
|
+
# Configurable attribute
|
|
7
|
+
module ClassMethods
|
|
8
|
+
# @!attribute [w] model_servicer
|
|
9
|
+
def model_servicer=(model_servicer)
|
|
10
|
+
ModuleUtils.inheritance_check model_servicer, application_servicer
|
|
11
|
+
@model_servicer = model_servicer
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @!attribute [r] model_servicer
|
|
15
|
+
# If Wallaby doesn't get it right, please specify the **model_servicer**.
|
|
16
|
+
# @example To set model servicer
|
|
17
|
+
# class Admin::ProductionsController < Admin::ApplicationController
|
|
18
|
+
# self.model_servicer = ProductServicer
|
|
19
|
+
# end
|
|
20
|
+
# @return [Class] model servicer
|
|
21
|
+
# @raise [ArgumentError] when **model_servicer** doesn't inherit from **application_servicer**
|
|
22
|
+
# @see Wallaby::ModelServicer
|
|
23
|
+
# @since 5.2.0
|
|
24
|
+
attr_reader :model_servicer
|
|
25
|
+
|
|
26
|
+
# @!attribute [w] application_servicer
|
|
27
|
+
def application_servicer=(application_servicer)
|
|
28
|
+
ModuleUtils.inheritance_check model_servicer, application_servicer
|
|
29
|
+
@application_servicer = application_servicer
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @!attribute [r] application_servicer
|
|
33
|
+
# The **application_servicer** is as the base class of {#model_servicer}.
|
|
34
|
+
# @example To set application decorator:
|
|
35
|
+
# class Admin::ApplicationController < Wallaby::ResourcesController
|
|
36
|
+
# self.application_servicer = AnotherApplicationServicer
|
|
37
|
+
# end
|
|
38
|
+
# @return [Class] application decorator
|
|
39
|
+
# @raise [ArgumentError] when **model_servicer** doesn't inherit from **application_servicer**
|
|
40
|
+
# @see Wallaby::ModelServicer
|
|
41
|
+
# @since 5.2.0
|
|
42
|
+
def application_servicer
|
|
43
|
+
@application_servicer ||= ModuleUtils.try_to superclass, :application_servicer
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Model servicer for current modal class. It comes from:
|
|
48
|
+
#
|
|
49
|
+
# - controller configuration {Wallaby::Servicable::ClassMethods#model_servicer .model_servicer}
|
|
50
|
+
# - a generic servicer based on {Wallaby::Servicable::ClassMethods#application_servicer .application_servicer}
|
|
51
|
+
# @return [Wallaby::ModelServicer] model servicer
|
|
52
|
+
# @since 5.2.0
|
|
53
|
+
def current_servicer
|
|
54
|
+
@current_servicer ||=
|
|
55
|
+
(controller_to_get(:model_servicer) \
|
|
56
|
+
|| Map.servicer_map(current_model_class, controller_to_get(:application_servicer))).try do |klass|
|
|
57
|
+
Rails.logger.info %( - Current servicer: #{klass})
|
|
58
|
+
klass.new current_model_class, current_authorizer, current_model_decorator
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @deprecated Use {#current_servicer} instead. It will be removed from 5.3.*
|
|
63
|
+
def current_model_service
|
|
64
|
+
Utils.deprecate 'deprecation.current_model_service', caller: caller
|
|
65
|
+
current_servicer
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Shared helpers
|
|
5
|
+
module SharedHelpers
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
# Fetch value for given attribute.
|
|
9
|
+
#
|
|
10
|
+
# If it's used in controller, it will fetch it from class attribute.
|
|
11
|
+
# If it's used in view, it will fetch it from controller.
|
|
12
|
+
# @param attribute_name [String, Symbol] instance attribute name
|
|
13
|
+
# @param class_attribute_name [String, Symbol] class attribute name
|
|
14
|
+
# @return [Object] the value
|
|
15
|
+
def controller_to_get(attribute_name, class_attribute_name = nil)
|
|
16
|
+
class_attribute_name ||= attribute_name
|
|
17
|
+
return ModuleUtils.try_to self.class, class_attribute_name if is_a? ::ActionController::Base # controller?
|
|
18
|
+
|
|
19
|
+
ModuleUtils.try_to controller, attribute_name # view?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Theme related methods
|
|
5
|
+
module Themeable
|
|
6
|
+
# Configurable attributes
|
|
7
|
+
module ClassMethods
|
|
8
|
+
# @!attribute [w] theme_name
|
|
9
|
+
def theme_name=(theme_name)
|
|
10
|
+
layout theme_name
|
|
11
|
+
@theme_name = theme_name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @!attribute [r] theme_name
|
|
15
|
+
# The theme name is used to apply a set of frontend (html/css/javascript) implementation.
|
|
16
|
+
#
|
|
17
|
+
# When theme name is set to e.g. `custom_theme`, the following changes will be made:
|
|
18
|
+
#
|
|
19
|
+
# - layout will be set to the same name `custom_theme`
|
|
20
|
+
# - it will be added to the partial lookup prefixes right on top of `wallaby/resources` prefix.
|
|
21
|
+
#
|
|
22
|
+
# Once theme name is set, all its controller subclasses will inherit the same theme name
|
|
23
|
+
# @example To set an theme name:
|
|
24
|
+
# class Admin::ApplicationController < Wallaby::ResourcesController
|
|
25
|
+
# self.theme_name = 'admin_theme'
|
|
26
|
+
# end
|
|
27
|
+
# @return [String, Symbol, nil] theme name
|
|
28
|
+
# @since 5.2.0
|
|
29
|
+
def theme_name
|
|
30
|
+
@theme_name ||= ModuleUtils.try_to superclass, :theme_name
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [String, Symbol, nil] theme name
|
|
35
|
+
# @since 5.2.0
|
|
36
|
+
def current_theme_name
|
|
37
|
+
controller_to_get __callee__, :theme_name
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Resource Decorator base class, designed for decorator pattern.
|
|
5
|
+
# @see Wallaby::ModelDecorator
|
|
6
|
+
class ResourceDecorator
|
|
7
|
+
extend Baseable::ClassMethods
|
|
8
|
+
|
|
9
|
+
DELEGATE_METHODS =
|
|
10
|
+
ModelDecorator.public_instance_methods(false) + Fieldable.public_instance_methods(false) - %i(model_class)
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
delegate(*DELEGATE_METHODS, to: :model_decorator, allow_nil: true)
|
|
14
|
+
|
|
15
|
+
# @!attribute [w] model_class
|
|
16
|
+
attr_writer :model_class
|
|
17
|
+
|
|
18
|
+
# @!attribute [r] model_class
|
|
19
|
+
# Return associated model class, e.g. return **Product** for **ProductDecorator**.
|
|
20
|
+
#
|
|
21
|
+
# If Wallaby can't recognise the model class for Decorator, it's required to be configured as below example:
|
|
22
|
+
# @example To configure model class
|
|
23
|
+
# class Admin::ProductDecorator < Admin::ApplicationDecorator
|
|
24
|
+
# self.model_class = Product
|
|
25
|
+
# end
|
|
26
|
+
# @example To configure model class for version below 5.2.0
|
|
27
|
+
# class Admin::ProductDecorator < Admin::ApplicationDecorator
|
|
28
|
+
# def self.model_class
|
|
29
|
+
# Product
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
# @return [Class] assoicated model class
|
|
33
|
+
# @return [nil] if current class is marked as base class
|
|
34
|
+
# @return [nil] if current class is the same as the value of {Wallaby::Configuration::Mapping#resource_decorator}
|
|
35
|
+
# @return [nil] if current class is {Wallaby::ResourceDecorator}
|
|
36
|
+
# @return [nil] if assoicated model class is not found
|
|
37
|
+
def model_class
|
|
38
|
+
return unless self < ResourceDecorator
|
|
39
|
+
return if base_class? || self == Wallaby.configuration.mapping.resource_decorator
|
|
40
|
+
|
|
41
|
+
@model_class ||= Map.model_class_map(name.gsub(/(^#{namespace}::)|(Decorator$)/, EMPTY_STRING))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @!attribute [w] application_decorator
|
|
45
|
+
def application_decorator=(application_decorator)
|
|
46
|
+
ModuleUtils.inheritance_check self, application_decorator
|
|
47
|
+
@application_decorator = application_decorator
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @note This attribute have to be the same as the one defined in the controller in order to make things working.
|
|
51
|
+
# see {Wallaby::Decoratable::ClassMethods#application_decorator}
|
|
52
|
+
# @!attribute [r] application_decorator
|
|
53
|
+
# Assoicated base class.
|
|
54
|
+
#
|
|
55
|
+
# Wallaby will try to get the application decorator class from current class's ancestors chain.
|
|
56
|
+
# For instance, if current class is **ProductDecorator**, and it inherits from **CoreDecorator**,
|
|
57
|
+
# then Wallaby will return application decorator class **CoreDecorator**.
|
|
58
|
+
#
|
|
59
|
+
# However, there is a chance that Wallaby doesn't get it right.
|
|
60
|
+
# For instance, if **CoreDecorator** in the above example inherits from **Admin::ApplicationDecorator**, and
|
|
61
|
+
# the controller that needs **ProductDecorator** has set its **application_decorator** to
|
|
62
|
+
# **Admin::ApplicationDecorator**, then it's needed to configure **application_decorator** as the example
|
|
63
|
+
# describes
|
|
64
|
+
# @example To set application decorator class
|
|
65
|
+
# class ProductController < Admin::ApplicationController
|
|
66
|
+
# self.application_decorator = Admin::ApplicationDecorator
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# class CoreDecorator < Admin::ApplicationDecorator
|
|
70
|
+
# base_class!
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# class ProductDecorator < CoreDecorator
|
|
74
|
+
# self.application_decorator = Admin::ApplicationDecorator
|
|
75
|
+
# end
|
|
76
|
+
# @return [Class] assoicated base class.
|
|
77
|
+
# @return [nil] if assoicated base class is not found from its ancestors chain
|
|
78
|
+
# @raise [ArgumentError] when current class doesn't inherit from given value
|
|
79
|
+
# @since 5.2.0
|
|
80
|
+
def application_decorator
|
|
81
|
+
@application_decorator ||= ancestors.find { |parent| parent < ResourceDecorator && !parent.model_class }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Return associated model decorator.
|
|
85
|
+
#
|
|
86
|
+
# Fetch model decorator instance from cached map using keys {.model_class} and {.application_decorator}
|
|
87
|
+
# so that model decorator can be used in its sub classes declaration/scope.
|
|
88
|
+
# @param model_class [Class]
|
|
89
|
+
# @return [Wallaby::ModelDecorator]
|
|
90
|
+
def model_decorator(model_class = self.model_class)
|
|
91
|
+
return unless self < ResourceDecorator || model_class
|
|
92
|
+
|
|
93
|
+
Map.model_decorator_map model_class, application_decorator
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @!attribute [w] h
|
|
97
|
+
attr_writer :h
|
|
98
|
+
|
|
99
|
+
# @!attribute [r] h
|
|
100
|
+
# @return [ActionView::Base]
|
|
101
|
+
# {Wallaby::Configuration::Mapping#resources_controller resources controller}'s helpers
|
|
102
|
+
def h
|
|
103
|
+
@h ||= Wallaby.configuration.mapping.resources_controller.helpers
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @!attribute [r] resource
|
|
108
|
+
# @return [Object]
|
|
109
|
+
attr_reader :resource
|
|
110
|
+
|
|
111
|
+
# @!attribute [r] model_decorator
|
|
112
|
+
# @return [Wallaby::ModelDecorator]
|
|
113
|
+
attr_reader :model_decorator
|
|
114
|
+
|
|
115
|
+
# @return [ActionView::Base]
|
|
116
|
+
# {Wallaby::Configuration::Mapping#resources_controller resources controller}'s helpers
|
|
117
|
+
# @see .h
|
|
118
|
+
def h
|
|
119
|
+
self.class.h
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
delegate(*DELEGATE_METHODS, to: :model_decorator)
|
|
123
|
+
# NOTE: this delegation is to make url helper method working properly with resource decorator instance
|
|
124
|
+
delegate :to_s, :to_param, to: :resource
|
|
125
|
+
|
|
126
|
+
# @param resource [Object]
|
|
127
|
+
def initialize(resource)
|
|
128
|
+
@resource = resource
|
|
129
|
+
@model_decorator = self.class.model_decorator(model_class)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @return [Class] resource's class
|
|
133
|
+
def model_class
|
|
134
|
+
resource.class
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @param field_name [String, Symbol]
|
|
138
|
+
# @return [Object] value of given field name
|
|
139
|
+
def value_of(field_name)
|
|
140
|
+
return unless field_name
|
|
141
|
+
|
|
142
|
+
resource.try field_name
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Guess the title for given resource.
|
|
146
|
+
#
|
|
147
|
+
# It falls back to primary key value when no text field is found.
|
|
148
|
+
# @return [String] a label
|
|
149
|
+
def to_label
|
|
150
|
+
# NOTE: `.to_s` at the end is to ensure String is returned that won't cause any
|
|
151
|
+
# issue when `#to_label` is used in a link_to block. Coz integer is ignored.
|
|
152
|
+
(model_decorator.guess_title(resource) || primary_key_value).to_s
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @return [Hash, Array] validation/result errors
|
|
156
|
+
def errors
|
|
157
|
+
model_decorator.form_active_errors(resource)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# @return [Object] primary key value
|
|
161
|
+
def primary_key_value
|
|
162
|
+
resource.try primary_key
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @return [ActiveModel::Name]
|
|
166
|
+
def model_name
|
|
167
|
+
ModuleUtils.try_to(resource, :model_name) || ActiveModel::Name.new(model_class)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# @return [nil] if no primary key
|
|
171
|
+
# @return [Array<String>] primary key
|
|
172
|
+
def to_key
|
|
173
|
+
key = ModuleUtils.try_to(resource, primary_key)
|
|
174
|
+
key ? [key] : nil
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Delegate missing method to {#resource}
|
|
178
|
+
def method_missing(method_id, *args, &block)
|
|
179
|
+
return super unless resource.respond_to? method_id
|
|
180
|
+
|
|
181
|
+
resource.try method_id, *args, &block
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Delegate missing method check to context
|
|
185
|
+
def respond_to_missing?(method_id, _include_private)
|
|
186
|
+
resource.respond_to?(method_id) || super
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Custom form builder to add more helper functions
|
|
5
|
+
class FormBuilder < ::ActionView::Helpers::FormBuilder
|
|
6
|
+
# Return error class if there is error
|
|
7
|
+
# @param field_name [String/Symbol]
|
|
8
|
+
# @return [String]
|
|
9
|
+
def error_class(field_name)
|
|
10
|
+
'has-error' if object.errors[field_name].present?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Build up the HTML for displaying error messages
|
|
14
|
+
# @param field_name [String/Symbol]
|
|
15
|
+
# @return [String] HTML
|
|
16
|
+
def error_messages(field_name)
|
|
17
|
+
errors = Array object.errors[field_name]
|
|
18
|
+
return if errors.blank?
|
|
19
|
+
|
|
20
|
+
content_tag :ul, class: 'errors' do
|
|
21
|
+
errors.each do |message|
|
|
22
|
+
concat content_tag :li, content_tag(
|
|
23
|
+
:small, raw(message) # rubocop:disable Rails/OutputSafety
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Extend label to accept proc type `text` argument
|
|
30
|
+
# @see ActionView::Helpers::FormBuilder#label
|
|
31
|
+
def label(method, text = nil, options = {}, &block)
|
|
32
|
+
text = instance_exec(&text) if text.is_a?(Proc)
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Extend select to accept proc type `choices` argument
|
|
37
|
+
# @see ActionView::Helpers::FormBuilder#select
|
|
38
|
+
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
|
39
|
+
choices = instance_exec(&choices) if choices.is_a?(Proc)
|
|
40
|
+
super
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
protected
|
|
44
|
+
|
|
45
|
+
# Delegate missing method to `@template`
|
|
46
|
+
def method_missing(method, *args, &block)
|
|
47
|
+
return super unless @template.respond_to? method
|
|
48
|
+
|
|
49
|
+
# Delegate the method so that we don't come in here the next time
|
|
50
|
+
# when same method is called
|
|
51
|
+
self.class.delegate method, to: :@template
|
|
52
|
+
@template.public_send method, *args, &block
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Delegate missing method check to `@template`
|
|
56
|
+
def respond_to_missing?(method, _include_private)
|
|
57
|
+
@template.respond_to?(method) || super
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|