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.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +31 -0
  4. data/app/controllers/wallaby/application_controller.rb +84 -0
  5. data/app/controllers/wallaby/resources_controller.rb +381 -0
  6. data/app/controllers/wallaby/secure_controller.rb +81 -0
  7. data/app/security/ability.rb +13 -0
  8. data/config/locales/wallaby.en.yml +140 -0
  9. data/config/locales/wallaby_class.en.yml +30 -0
  10. data/config/routes.rb +39 -0
  11. data/lib/adaptors/wallaby/custom.rb +7 -0
  12. data/lib/adaptors/wallaby/custom/default_provider.rb +9 -0
  13. data/lib/adaptors/wallaby/custom/model_decorator.rb +71 -0
  14. data/lib/adaptors/wallaby/custom/model_finder.rb +13 -0
  15. data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +14 -0
  16. data/lib/adaptors/wallaby/custom/model_service_provider.rb +48 -0
  17. data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +72 -0
  18. data/lib/authorizers/wallaby/default_authorization_provider.rb +58 -0
  19. data/lib/authorizers/wallaby/model_authorizer.rb +100 -0
  20. data/lib/authorizers/wallaby/pundit_authorization_provider.rb +89 -0
  21. data/lib/concerns/wallaby/authorizable.rb +103 -0
  22. data/lib/concerns/wallaby/baseable.rb +36 -0
  23. data/lib/concerns/wallaby/decoratable.rb +101 -0
  24. data/lib/concerns/wallaby/defaultable.rb +38 -0
  25. data/lib/concerns/wallaby/engineable.rb +61 -0
  26. data/lib/concerns/wallaby/fieldable.rb +78 -0
  27. data/lib/concerns/wallaby/paginatable.rb +72 -0
  28. data/lib/concerns/wallaby/rails_overridden_methods.rb +42 -0
  29. data/lib/concerns/wallaby/resourcable.rb +149 -0
  30. data/lib/concerns/wallaby/servicable.rb +68 -0
  31. data/lib/concerns/wallaby/shared_helpers.rb +22 -0
  32. data/lib/concerns/wallaby/themeable.rb +40 -0
  33. data/lib/decorators/wallaby/resource_decorator.rb +189 -0
  34. data/lib/errors/wallaby/cell_handling.rb +6 -0
  35. data/lib/errors/wallaby/forbidden.rb +6 -0
  36. data/lib/errors/wallaby/general_error.rb +6 -0
  37. data/lib/errors/wallaby/invalid_error.rb +6 -0
  38. data/lib/errors/wallaby/model_not_found.rb +11 -0
  39. data/lib/errors/wallaby/not_authenticated.rb +6 -0
  40. data/lib/errors/wallaby/not_found.rb +6 -0
  41. data/lib/errors/wallaby/not_implemented.rb +6 -0
  42. data/lib/errors/wallaby/resource_not_found.rb +11 -0
  43. data/lib/errors/wallaby/unprocessable_entity.rb +6 -0
  44. data/lib/forms/wallaby/form_builder.rb +60 -0
  45. data/lib/helpers/wallaby/application_helper.rb +79 -0
  46. data/lib/helpers/wallaby/base_helper.rb +65 -0
  47. data/lib/helpers/wallaby/configuration_helper.rb +18 -0
  48. data/lib/helpers/wallaby/form_helper.rb +62 -0
  49. data/lib/helpers/wallaby/index_helper.rb +84 -0
  50. data/lib/helpers/wallaby/links_helper.rb +213 -0
  51. data/lib/helpers/wallaby/resources_helper.rb +52 -0
  52. data/lib/helpers/wallaby/secure_helper.rb +54 -0
  53. data/lib/helpers/wallaby/styling_helper.rb +82 -0
  54. data/lib/interfaces/wallaby/mode.rb +72 -0
  55. data/lib/interfaces/wallaby/model_authorization_provider.rb +99 -0
  56. data/lib/interfaces/wallaby/model_decorator.rb +168 -0
  57. data/lib/interfaces/wallaby/model_finder.rb +12 -0
  58. data/lib/interfaces/wallaby/model_pagination_provider.rb +107 -0
  59. data/lib/interfaces/wallaby/model_service_provider.rb +84 -0
  60. data/lib/paginators/wallaby/model_paginator.rb +115 -0
  61. data/lib/paginators/wallaby/resource_paginator.rb +12 -0
  62. data/lib/parsers/wallaby/parser.rb +34 -0
  63. data/lib/renderers/wallaby/cell.rb +137 -0
  64. data/lib/renderers/wallaby/cell_resolver.rb +89 -0
  65. data/lib/renderers/wallaby/custom_lookup_context.rb +64 -0
  66. data/lib/renderers/wallaby/custom_partial_renderer.rb +33 -0
  67. data/lib/renderers/wallaby/custom_renderer.rb +16 -0
  68. data/lib/responders/wallaby/json_api_responder.rb +101 -0
  69. data/lib/responders/wallaby/resources_responder.rb +28 -0
  70. data/lib/routes/wallaby/resources_router.rb +72 -0
  71. data/lib/servicers/wallaby/model_servicer.rb +154 -0
  72. data/lib/services/wallaby/engine_name_finder.rb +22 -0
  73. data/lib/services/wallaby/engine_url_for.rb +46 -0
  74. data/lib/services/wallaby/link_options_normalizer.rb +19 -0
  75. data/lib/services/wallaby/map/mode_mapper.rb +27 -0
  76. data/lib/services/wallaby/map/model_class_collector.rb +49 -0
  77. data/lib/services/wallaby/map/model_class_mapper.rb +38 -0
  78. data/lib/services/wallaby/prefixes_builder.rb +66 -0
  79. data/lib/services/wallaby/sorting/hash_builder.rb +19 -0
  80. data/lib/services/wallaby/sorting/link_builder.rb +69 -0
  81. data/lib/services/wallaby/sorting/next_builder.rb +63 -0
  82. data/lib/services/wallaby/sorting/single_builder.rb +20 -0
  83. data/lib/services/wallaby/type_renderer.rb +50 -0
  84. data/lib/support/action_dispatch/routing/mapper.rb +75 -0
  85. data/lib/tree/wallaby/node.rb +25 -0
  86. data/lib/utils/wallaby/cell_utils.rb +34 -0
  87. data/lib/utils/wallaby/field_utils.rb +43 -0
  88. data/lib/utils/wallaby/filter_utils.rb +20 -0
  89. data/lib/utils/wallaby/model_utils.rb +51 -0
  90. data/lib/utils/wallaby/module_utils.rb +46 -0
  91. data/lib/utils/wallaby/params_utils.rb +14 -0
  92. data/lib/utils/wallaby/preload_utils.rb +44 -0
  93. data/lib/utils/wallaby/test_utils.rb +34 -0
  94. data/lib/utils/wallaby/utils.rb +27 -0
  95. data/lib/wallaby/configuration.rb +103 -0
  96. data/lib/wallaby/configuration/features.rb +24 -0
  97. data/lib/wallaby/configuration/mapping.rb +140 -0
  98. data/lib/wallaby/configuration/metadata.rb +23 -0
  99. data/lib/wallaby/configuration/models.rb +46 -0
  100. data/lib/wallaby/configuration/pagination.rb +30 -0
  101. data/lib/wallaby/configuration/security.rb +98 -0
  102. data/lib/wallaby/configuration/sorting.rb +28 -0
  103. data/lib/wallaby/constants.rb +45 -0
  104. data/lib/wallaby/core.rb +117 -0
  105. data/lib/wallaby/core/version.rb +7 -0
  106. data/lib/wallaby/engine.rb +43 -0
  107. data/lib/wallaby/map.rb +170 -0
  108. metadata +222 -0
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Decorator related attributes
5
+ module Decoratable
6
+ # Configurable attribute
7
+ module ClassMethods
8
+ # @!attribute [w] resource_decorator
9
+ def resource_decorator=(resource_decorator)
10
+ ModuleUtils.inheritance_check resource_decorator, application_decorator
11
+ @resource_decorator = resource_decorator
12
+ end
13
+
14
+ # @!attribute [r] resource_decorator
15
+ # Resource decorator will be used for its metadata info and decoration methods.
16
+ #
17
+ # If Wallaby doesn't get it right, please specify the **resource_decorator**.
18
+ # @example To set resource decorator
19
+ # class Admin::ProductionsController < Admin::ApplicationController
20
+ # self.resource_decorator = ProductDecorator
21
+ # end
22
+ # @return [Class] resource decorator
23
+ # @raise [ArgumentError] when **resource_decorator** doesn't inherit from **application_decorator**
24
+ # @see Wallaby::ResourceDecorator
25
+ # @since 5.2.0
26
+ attr_reader :resource_decorator
27
+
28
+ # @!attribute [w] application_decorator
29
+ def application_decorator=(application_decorator)
30
+ ModuleUtils.inheritance_check resource_decorator, application_decorator
31
+ @application_decorator = application_decorator
32
+ end
33
+
34
+ # @!attribute [r] application_decorator
35
+ # The **application_decorator** is as the base class of {#resource_decorator}.
36
+ # @example To set application decorator:
37
+ # class Admin::ApplicationController < Wallaby::ResourcesController
38
+ # self.application_decorator = AnotherApplicationDecorator
39
+ # end
40
+ # @raise [ArgumentError] when **resource_decorator** doesn't inherit from **application_decorator**
41
+ # @return [Class] application decorator
42
+ # @see Wallaby::ResourceDecorator
43
+ # @since 5.2.0
44
+ def application_decorator
45
+ @application_decorator ||= ModuleUtils.try_to superclass, :application_decorator
46
+ end
47
+ end
48
+
49
+ # Get current model decorator. It comes from
50
+ #
51
+ # - model decorator for {Wallaby::Decoratable::ClassMethods#resource_decorator resource_decorator}
52
+ # - otherwise, model decorator for {Wallaby::Decoratable::ClassMethods#application_decorator application_decorator}
53
+ #
54
+ # Model decorator stores the information of **metadata** and **field_names** for **index**/**show**/**form** action.
55
+ # @return [Wallaby::ModelDecorator] current model decorator for this request
56
+ def current_model_decorator
57
+ @current_model_decorator ||=
58
+ current_decorator.try(:model_decorator) || \
59
+ Map.model_decorator_map(current_model_class, controller_to_get(:application_decorator))
60
+ end
61
+
62
+ # Get current resource decorator. It comes from
63
+ #
64
+ # - {Wallaby::Decoratable::ClassMethods#resource_decorator resource_decorator}
65
+ # - otherwise, {Wallaby::Decoratable::ClassMethods#application_decorator application_decorator}
66
+ # @return [Wallaby::ResourceDecorator] current resource decorator for this request
67
+ def current_decorator
68
+ @current_decorator ||=
69
+ (controller_to_get(:resource_decorator) || \
70
+ Map.resource_decorator_map(current_model_class, controller_to_get(:application_decorator))).tap do |decorator|
71
+ Rails.logger.info %( - Current decorator: #{decorator})
72
+ end
73
+ end
74
+
75
+ # Get current fields metadata for current action name.
76
+ # @return [Hash] current fields metadata
77
+ def current_fields
78
+ @current_fields ||=
79
+ ModuleUtils.try_to current_model_decorator, :"#{FORM_ACTIONS[action_name] || action_name}_fields"
80
+ end
81
+
82
+ # Wrap resource(s) with decorator(s).
83
+ # @param resource [Object, Enumerable]
84
+ # @return [Wallaby::ResourceDecorator, Enumerable<Wallaby::ResourceDecorator>] decorator(s)
85
+ def decorate(resource)
86
+ return resource if resource.is_a? ResourceDecorator
87
+ return resource.map { |item| decorate item } if resource.respond_to? :map
88
+
89
+ decorator = Map.resource_decorator_map resource.class, controller_to_get(:application_decorator)
90
+ decorator ? decorator.new(resource) : resource
91
+ end
92
+
93
+ # @param resource [Object, Wallaby::ResourceDecorator]
94
+ # @return [Object] the unwrapped resource object
95
+ def extract(resource)
96
+ return resource.resource if resource.is_a? ResourceDecorator
97
+
98
+ resource
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Defaults related methods
5
+ module Defaultable
6
+ protected
7
+
8
+ # Set default options for create action
9
+ # @param options [Hash]
10
+ # @return [Hash] updated options with default values
11
+ def set_defaults_for(action, options)
12
+ case action.try(:to_sym)
13
+ when :create, :update then assign_create_and_update_defaults_with options
14
+ when :destroy then assign_destroy_defaults_with options
15
+ end
16
+ options
17
+ end
18
+
19
+ # @param options [Hash]
20
+ # @return [Hash] updated options with default values
21
+ def assign_create_and_update_defaults_with(options)
22
+ options[:params] ||= resource_params
23
+ options[:location] ||= -> { helpers.show_path resource, is_resource: params[:resource] }
24
+ end
25
+
26
+ # @param options [Hash]
27
+ # @return [Hash] updated options with default values
28
+ def assign_destroy_defaults_with(options)
29
+ options[:params] ||= params
30
+ options[:location] ||=
31
+ if params[:resource]
32
+ helpers.show_path resource, is_resource: params[:resource]
33
+ else
34
+ helpers.index_path current_model_class
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Engine related helper methods for both controller and view
5
+ module Engineable
6
+ # Configurable attribute
7
+ module ClassMethods
8
+ # @!attribute [w] engine_name
9
+ attr_writer :engine_name
10
+
11
+ # @!attribute [r] engine_name
12
+ # The engine name will be used to handle URLs.
13
+ #
14
+ # So when to set this engine name? When Wallaby doesn't know what is the correct engine helper to use.
15
+ # @example To set an engine name:
16
+ # class Admin::ApplicationController < Wallaby::ResourcesController
17
+ # self.engine_name = 'admin_engine'
18
+ # end
19
+ # @return [String, Symbol, nil] engine name
20
+ # @since 5.2.0
21
+ def engine_name
22
+ @engine_name ||= ModuleUtils.try_to superclass, :engine_name
23
+ end
24
+ end
25
+
26
+ # This engine helper is used to access URL helpers of Wallaby engine.
27
+ #
28
+ # Considering **Wallaby** is mounted at the following paths:
29
+ #
30
+ # ```
31
+ # mount Wallaby::Engine, at: '/admin'
32
+ # mount Wallaby::Engine, at: '/inner', as: :inner_engine, defaults: { resources_controller: InnerController }
33
+ # ```
34
+ #
35
+ # If `/inner` is current script name, `current_engine` is same as `inner_engine`.
36
+ # Then it's possible to access URL helpers like this:
37
+ #
38
+ # ```
39
+ # current_engine.resources_path resources: 'products'
40
+ # ```
41
+ # @return [ActionDispatch::Routing::RoutesProxy] engine for current request
42
+ def current_engine
43
+ @current_engine ||= ModuleUtils.try_to self, current_engine_name
44
+ end
45
+
46
+ # Find out the engine name under current script name.
47
+ #
48
+ # Considering **Wallaby** is mounted at the following paths:
49
+ #
50
+ # ```
51
+ # mount Wallaby::Engine, at: '/admin'
52
+ # mount Wallaby::Engine, at: '/inner', as: :inner_engine, defaults: { resources_controller: InnerController }
53
+ # ```
54
+ #
55
+ # If `/inner` is current script name, then `current_engine_name` returns `'inner_engine'`.
56
+ # @return [String] engine name for current request
57
+ def current_engine_name
58
+ @current_engine_name ||= controller_to_get(__callee__, :engine_name) || EngineNameFinder.find(request.env)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Field helper for model decorator
5
+ module Fieldable
6
+ # @param field_name [String, Symbol] field name
7
+ # @return [Hash] metadata information for a given field
8
+ def metadata_of(field_name)
9
+ fields[field_name] || {}
10
+ end
11
+
12
+ # @param field_name [String, Symbol] field name
13
+ # @return [String] label for a given field
14
+ def label_of(field_name)
15
+ metadata_of(field_name)[:label] || field_name.to_s.humanize
16
+ end
17
+
18
+ # @param field_name [String, Symbol] field name
19
+ # @return [String, Symbol] type for a given field
20
+ def type_of(field_name)
21
+ validate_presence_of field_name, metadata_of(field_name)[:type]
22
+ end
23
+
24
+ # @param field_name [String, Symbol] field name
25
+ # @return [Hash] index metadata information for a given field
26
+ def index_metadata_of(field_name)
27
+ index_fields[field_name] || {}
28
+ end
29
+
30
+ # @param field_name [String, Symbol] field name
31
+ # @return [String] index label for a given field
32
+ def index_label_of(field_name)
33
+ index_metadata_of(field_name)[:label] || field_name.to_s.humanize
34
+ end
35
+
36
+ # @param field_name [String, Symbol] field name
37
+ # @return [String, Symbol] index type for a given field
38
+ def index_type_of(field_name)
39
+ validate_presence_of field_name, index_metadata_of(field_name)[:type]
40
+ end
41
+
42
+ # @param field_name [String, Symbol] field name
43
+ # @return [Hash] show metadata information for a given field
44
+ def show_metadata_of(field_name)
45
+ show_fields[field_name] || {}
46
+ end
47
+
48
+ # @param field_name [String, Symbol] field name
49
+ # @return [String] show label for a given field
50
+ def show_label_of(field_name)
51
+ show_metadata_of(field_name)[:label] || field_name.to_s.humanize
52
+ end
53
+
54
+ # @param field_name [String, Symbol] field name
55
+ # @return [String, Symbol] show type for a given field
56
+ def show_type_of(field_name)
57
+ validate_presence_of field_name, show_metadata_of(field_name)[:type]
58
+ end
59
+
60
+ # @param field_name [String, Symbol] field name
61
+ # @return [Hash] form metadata information for a given field
62
+ def form_metadata_of(field_name)
63
+ form_fields[field_name] || {}
64
+ end
65
+
66
+ # @param field_name [String, Symbol] field name
67
+ # @return [String] form label for a given field
68
+ def form_label_of(field_name)
69
+ form_metadata_of(field_name)[:label] || field_name.to_s.humanize
70
+ end
71
+
72
+ # @param field_name [String, Symbol] field name
73
+ # @return [String, Symbol] form type for a given field
74
+ def form_type_of(field_name)
75
+ validate_presence_of field_name, form_metadata_of(field_name)[:type]
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Paginator related attributes
5
+ module Paginatable
6
+ # Configurable attribute
7
+ module ClassMethods
8
+ # @!attribute [w] model_paginator
9
+ def model_paginator=(model_paginator)
10
+ ModuleUtils.inheritance_check model_paginator, application_paginator
11
+ @model_paginator = model_paginator
12
+ end
13
+
14
+ # @!attribute [r] model_paginator
15
+ # If Wallaby doesn't get it right, please specify the **model_paginator**.
16
+ # @example To set model paginator
17
+ # class Admin::ProductionsController < Admin::ApplicationController
18
+ # self.model_paginator = ProductPaginator
19
+ # end
20
+ # @return [Class] model paginator
21
+ # @raise [ArgumentError] when **model_paginator** doesn't inherit from **application_paginator**
22
+ # @see Wallaby::ModelPaginator
23
+ # @since 5.2.0
24
+ attr_reader :model_paginator
25
+
26
+ # @!attribute [w] application_paginator
27
+ def application_paginator=(application_paginator)
28
+ ModuleUtils.inheritance_check model_paginator, application_paginator
29
+ @application_paginator = application_paginator
30
+ end
31
+
32
+ # @!attribute [r] application_paginator
33
+ # The **application_paginator** is as the base class of {#model_paginator}.
34
+ # @example To set application decorator:
35
+ # class Admin::ApplicationController < Wallaby::ResourcesController
36
+ # self.application_paginator = AnotherApplicationPaginator
37
+ # end
38
+ # @return [Class] application decorator
39
+ # @raise [ArgumentError] when **model_paginator** doesn't inherit from **application_paginator**
40
+ # @see Wallaby::ModelPaginator
41
+ # @since 5.2.0
42
+ def application_paginator
43
+ @application_paginator ||= ModuleUtils.try_to superclass, :application_paginator
44
+ end
45
+ end
46
+
47
+ # Model paginator for current modal class. It comes from:
48
+ #
49
+ # - controller configuration {Wallaby::Paginatable::ClassMethods#model_paginator .model_paginator}
50
+ # - a generic paginator based on {Wallaby::Paginatable::ClassMethods#application_paginator .application_paginator}
51
+ # @return [Class] model paginator class
52
+ def current_paginator
53
+ @current_paginator ||=
54
+ (controller_to_get(:model_paginator) \
55
+ || Map.paginator_map(current_model_class, controller_to_get(:application_paginator))).try do |klass|
56
+ Rails.logger.info %( - Current paginator: #{klass})
57
+ klass.new current_model_class, collection, params
58
+ end
59
+ end
60
+
61
+ # To paginate the collection but only when either `page` or `per` param is given,
62
+ # or HTML response is requested
63
+ # @param query [#each]
64
+ # @param options [Hash]
65
+ # @option options [Boolean] :paginate whether collection should be paginated
66
+ # @return [#each]
67
+ # @see Wallaby::ModelServicer#paginate
68
+ def paginate(query, options)
69
+ options[:paginate] ? current_servicer.paginate(query, params) : query
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # This is a collection of the helper methods that overrides the rails methods
5
+ module RailsOverriddenMethods
6
+ protected
7
+
8
+ # Override {https://github.com/rails/rails/blob/master/actionview/lib/action_view/view_paths.rb
9
+ # ActionView::ViewPaths::ClassMethods#_prefixes} to extend the prefixes for **ActionView::ViewPaths** to look up
10
+ # in below precedence from high to low:
11
+ #
12
+ # - :mounted_path/:resources_name/:action_prefix (e.g. `admin/products/index`)
13
+ # - :mounted_path/:resources_name (e.g. `admin/products`)
14
+ # - :controller_path/:action_prefix
15
+ # - :controller_path
16
+ # - :parent_controller_path/:action_prefix
17
+ # - :parent_controller_path
18
+ # - :more_parent_controller_path/:action_prefix
19
+ # - :more_parent_controller_path
20
+ # - :theme_name/:action_prefix
21
+ # - :theme_name
22
+ # - wallaby/resources/:action_prefix
23
+ # - wallaby/resources
24
+ # @return [Array<String>]
25
+ def _prefixes
26
+ @_prefixes ||= PrefixesBuilder.build(
27
+ origin_prefixes: super,
28
+ theme_name: current_theme_name,
29
+ resources_name: current_resources_name,
30
+ script_name: request.env[SCRIPT_NAME],
31
+ action_name: params[:action]
32
+ )
33
+ end
34
+
35
+ # Override to provide support for cell lookup
36
+ # @return [Wallaby::CustomLookupContext]
37
+ def lookup_context
38
+ @_lookup_context ||= # rubocop:disable Naming/MemoizedInstanceVariableName
39
+ CustomLookupContext.normalize(super, prefixes: _prefixes)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Resources related attributes
5
+ module Resourcable
6
+ # Configurable attribute
7
+ module ClassMethods
8
+ # @!attribute [w] model_class
9
+ attr_writer :model_class
10
+
11
+ # @!attribute [r] model_class
12
+ # This attribute will be used by the dynamic router to find out which
13
+ # controller to dispatch to. For example:
14
+ #
15
+ # `/admin/products` will be dispatched to the controller that has the
16
+ # model class `Product`.
17
+ # @return [Class] the model class for controller.
18
+ # @example It can be customized as below:
19
+ # ```
20
+ # self.model_class = Product
21
+ # ```
22
+ # Or
23
+ # ```
24
+ # def self.model_class; Product; end
25
+ # ```
26
+ # @example To set model paginator
27
+ # class Admin::ProductionsController < Admin::ApplicationController
28
+ # self.model_class = ProductResources
29
+ # end
30
+ # @return [Class] model paginator
31
+ # @raise [ArgumentError] when **model_class** doesn't inherit from **application_paginator**
32
+ # @see Wallaby::ModelResources
33
+ def model_class
34
+ return unless self < ResourcesController
35
+ return if base_class? || self == Wallaby.configuration.mapping.resources_controller
36
+
37
+ @model_class ||= Map.model_class_map(name.gsub(/(^#{namespace}::)|(Controller$)/, EMPTY_STRING))
38
+ end
39
+ end
40
+
41
+ # @return [String] resources name for current request
42
+ def current_resources_name
43
+ @current_resources_name ||= params[:resources]
44
+ end
45
+
46
+ # @return [Class] model class for current request
47
+ def current_model_class
48
+ @current_model_class ||=
49
+ controller_to_get(__callee__, :model_class) || Map.model_class_map(current_resources_name || controller_path)
50
+ end
51
+
52
+ # Shorthand of params[:id]
53
+ # @return [String, nil] ID param
54
+ def resource_id
55
+ params[:id]
56
+ end
57
+
58
+ # @note This is a template method that can be overridden by subclasses.
59
+ # This is a method to return collection for index page.
60
+ #
61
+ # It can be customized as below in subclasses:
62
+ #
63
+ # ```
64
+ # def collection
65
+ # # do something before the origin action
66
+ # options = {} # NOTE: see `options` parameter for more details
67
+ # collection! options do |query| # NOTE: this is better than using `super`
68
+ # # NOTE: make sure a collection is returned
69
+ # query.where(active: true)
70
+ # end
71
+ # end
72
+ # ```
73
+ #
74
+ # Otherwise, it can be replaced completely in subclasses:
75
+ #
76
+ # ```
77
+ # def collection
78
+ # # NOTE: pagination should happen here if needed
79
+ # # NOTE: make sure `@collection` and conditional assignment (the OR EQUAL) operator are used
80
+ # @collection ||= paginate Product.active
81
+ # end
82
+ # ```
83
+ # @param options [Hash] (since 5.2.0)
84
+ # @option options [ActionController::Parameters, Hash] :params parameters for collection query
85
+ # @option options [Boolean] :paginate see {Wallaby::Paginatable#paginate}
86
+ # @yield [collection] (since 5.2.0) a block to run to extend collection, e.g. call chain with more queries
87
+ # @return [#each] a collection of records
88
+ def collection(options = {}, &block)
89
+ @collection ||=
90
+ ModuleUtils.yield_for(
91
+ begin
92
+ options[:paginate] = true unless options.key?(:paginate)
93
+ options[:params] ||= params
94
+ paginate current_servicer.collection(options.delete(:params)), options
95
+ end,
96
+ &block
97
+ )
98
+ end
99
+
100
+ # @note This is a template method that can be overridden by subclasses.
101
+ # This is a method to return resource for pages except `index`.
102
+ #
103
+ # `WARN: It does not do mass assignment since 5.2.0.`
104
+ #
105
+ # It can be customized as below in subclasses:
106
+ #
107
+ # ```
108
+ # def resource
109
+ # # do something before the origin action
110
+ # options = {} # NOTE: see `options` parameter for more details
111
+ # resource! options do |object| # NOTE: this is better than using `super`
112
+ # object.preload_status_from_api
113
+ # # NOTE: make sure object is returned
114
+ # object
115
+ # end
116
+ # end
117
+ # ```
118
+ #
119
+ # Otherwise, it can be replaced completely in subclasses:
120
+ #
121
+ # ```
122
+ # def resource
123
+ # # NOTE: make sure `@resource` and conditional assignment (the OR EQUAL) operator are used
124
+ # @resource ||= resource_id.present? ? Product.find_by_slug(resource_id) : Product.new(arrival: true)
125
+ # end
126
+ # ```
127
+ # @param options [Hash] (since 5.2.0)
128
+ # @option options [Array<String>] :non_find_actions action names that shouldn't use resource find.
129
+ # (Default to `%w(index new create)`)
130
+ # @option options [ActionController::Parameters, Hash] :find_params parameters/options for resource finding
131
+ # @option options [ActionController::Parameters, Hash] :new_params parameters/options for new resource
132
+ # @yield [resource] (since 5.2.0) a block to run to extend resource, e.g. making change to the resource.
133
+ # Please make sure to return the resource at the end of block
134
+ # @return [Object] either persisted or unpersisted resource instance
135
+ # @raise [ResourceNotFound] if resource is nil
136
+ def resource(options = {}, &block)
137
+ @resource ||=
138
+ ModuleUtils.yield_for(
139
+ # this will testify both resource and resources
140
+ if resource_id.present? || !(options[:non_find_actions] || NON_FIND_ACTIONS).include?(action_name)
141
+ current_servicer.find resource_id, options[:find_params]
142
+ else
143
+ current_servicer.new options[:new_params]
144
+ end,
145
+ &block
146
+ )
147
+ end
148
+ end
149
+ end