wallaby-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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