actionpack 7.0.8 → 7.2.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 +4 -4
- data/CHANGELOG.md +76 -520
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +119 -106
- data/lib/abstract_controller/caching/fragments.rb +51 -52
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +94 -67
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +119 -91
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
- data/lib/abstract_controller/rendering.rb +14 -13
- data/lib/abstract_controller/translation.rb +15 -11
- data/lib/abstract_controller/url_for.rb +9 -5
- data/lib/abstract_controller.rb +8 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +77 -73
- data/lib/action_controller/base.rb +199 -141
- data/lib/action_controller/caching.rb +16 -11
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +21 -16
- data/lib/action_controller/log_subscriber.rb +19 -5
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +188 -174
- data/lib/action_controller/metal/content_security_policy.rb +26 -25
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +65 -54
- data/lib/action_controller/metal/default_headers.rb +6 -2
- data/lib/action_controller/metal/etag_with_flash.rb +4 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +18 -14
- data/lib/action_controller/metal/exceptions.rb +19 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +20 -16
- data/lib/action_controller/metal/helpers.rb +64 -67
- data/lib/action_controller/metal/http_authentication.rb +216 -199
- data/lib/action_controller/metal/implicit_render.rb +21 -17
- data/lib/action_controller/metal/instrumentation.rb +22 -12
- data/lib/action_controller/metal/live.rb +122 -92
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +58 -58
- data/lib/action_controller/metal/permissions_policy.rb +14 -13
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +110 -84
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -82
- data/lib/action_controller/metal/request_forgery_protection.rb +279 -161
- data/lib/action_controller/metal/rescue.rb +12 -8
- data/lib/action_controller/metal/streaming.rb +174 -132
- data/lib/action_controller/metal/strong_parameters.rb +598 -473
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +23 -14
- data/lib/action_controller/metal.rb +145 -61
- data/lib/action_controller/railtie.rb +25 -9
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +105 -66
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +155 -125
- data/lib/action_controller.rb +17 -3
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +28 -29
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +52 -45
- data/lib/action_dispatch/http/filter_parameters.rb +18 -8
- data/lib/action_dispatch/http/filter_redirect.rb +15 -1
- data/lib/action_dispatch/http/headers.rb +23 -21
- data/lib/action_dispatch/http/mime_negotiation.rb +37 -48
- data/lib/action_dispatch/http/mime_type.rb +60 -30
- data/lib/action_dispatch/http/mime_types.rb +5 -1
- data/lib/action_dispatch/http/parameters.rb +12 -10
- data/lib/action_dispatch/http/permissions_policy.rb +32 -34
- data/lib/action_dispatch/http/rack_cache.rb +4 -0
- data/lib/action_dispatch/http/request.rb +113 -79
- data/lib/action_dispatch/http/response.rb +136 -103
- data/lib/action_dispatch/http/upload.rb +19 -15
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +19 -6
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +18 -15
- data/lib/action_dispatch/journey/route.rb +12 -9
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +13 -10
- data/lib/action_dispatch/journey/routes.rb +6 -4
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +7 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +4 -0
- data/lib/action_dispatch/middleware/cookies.rb +192 -194
- data/lib/action_dispatch/middleware/debug_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/debug_locks.rb +18 -13
- data/lib/action_dispatch/middleware/debug_view.rb +9 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -27
- data/lib/action_dispatch/middleware/executor.rb +9 -1
- data/lib/action_dispatch/middleware/flash.rb +65 -46
- data/lib/action_dispatch/middleware/host_authorization.rb +22 -17
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -8
- data/lib/action_dispatch/middleware/reloader.rb +9 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +89 -83
- data/lib/action_dispatch/middleware/request_id.rb +15 -8
- data/lib/action_dispatch/middleware/server_timing.rb +8 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +7 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +14 -7
- data/lib/action_dispatch/middleware/session/cookie_store.rb +32 -25
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +9 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +42 -28
- data/lib/action_dispatch/middleware/ssl.rb +60 -45
- data/lib/action_dispatch/middleware/stack.rb +15 -9
- data/lib/action_dispatch/middleware/static.rb +40 -34
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +47 -38
- data/lib/action_dispatch/railtie.rb +12 -4
- data/lib/action_dispatch/request/session.rb +39 -27
- data/lib/action_dispatch/request/utils.rb +10 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +59 -9
- data/lib/action_dispatch/routing/mapper.rb +684 -638
- data/lib/action_dispatch/routing/polymorphic_routes.rb +70 -61
- data/lib/action_dispatch/routing/redirection.rb +52 -38
- data/lib/action_dispatch/routing/route_set.rb +105 -61
- data/lib/action_dispatch/routing/routes_proxy.rb +16 -19
- data/lib/action_dispatch/routing/url_for.rb +131 -122
- data/lib/action_dispatch/routing.rb +152 -150
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +27 -19
- data/lib/action_dispatch/system_testing/driver.rb +16 -22
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +53 -31
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +36 -26
- data/lib/action_dispatch/testing/assertions/routing.rb +203 -95
- data/lib/action_dispatch/testing/assertions.rb +5 -1
- data/lib/action_dispatch/testing/integration.rb +240 -229
- data/lib/action_dispatch/testing/request_encoder.rb +6 -1
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +14 -9
- data/lib/action_dispatch/testing/test_request.rb +4 -2
- data/lib/action_dispatch/testing/test_response.rb +34 -19
- data/lib/action_dispatch.rb +49 -22
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +18 -17
- metadata +88 -29
|
@@ -1,46 +1,68 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module AbstractController
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# Abstract Controller provides hooks during the life cycle of a controller action.
|
|
7
|
-
# Callbacks allow you to trigger logic during this cycle. Available callbacks are:
|
|
6
|
+
# # Abstract Controller Callbacks
|
|
8
7
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# * <tt>append_before_action</tt>
|
|
13
|
-
# * <tt>around_action</tt>
|
|
14
|
-
# * <tt>before_action</tt>
|
|
15
|
-
# * <tt>prepend_after_action</tt>
|
|
16
|
-
# * <tt>prepend_around_action</tt>
|
|
17
|
-
# * <tt>prepend_before_action</tt>
|
|
18
|
-
# * <tt>skip_after_action</tt>
|
|
19
|
-
# * <tt>skip_around_action</tt>
|
|
20
|
-
# * <tt>skip_before_action</tt>
|
|
21
|
-
#
|
|
22
|
-
# NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
|
|
8
|
+
# Abstract Controller provides hooks during the life cycle of a controller
|
|
9
|
+
# action. Callbacks allow you to trigger logic during this cycle. Available
|
|
10
|
+
# callbacks are:
|
|
23
11
|
#
|
|
12
|
+
# * `after_action`
|
|
13
|
+
# * `append_after_action`
|
|
14
|
+
# * `append_around_action`
|
|
15
|
+
# * `append_before_action`
|
|
16
|
+
# * `around_action`
|
|
17
|
+
# * `before_action`
|
|
18
|
+
# * `prepend_after_action`
|
|
19
|
+
# * `prepend_around_action`
|
|
20
|
+
# * `prepend_before_action`
|
|
21
|
+
# * `skip_after_action`
|
|
22
|
+
# * `skip_around_action`
|
|
23
|
+
# * `skip_before_action`
|
|
24
24
|
module Callbacks
|
|
25
25
|
extend ActiveSupport::Concern
|
|
26
26
|
|
|
27
|
-
# Uses ActiveSupport::Callbacks as the base functionality. For
|
|
28
|
-
#
|
|
29
|
-
#
|
|
27
|
+
# Uses ActiveSupport::Callbacks as the base functionality. For more details on
|
|
28
|
+
# the whole callback system, read the documentation for
|
|
29
|
+
# ActiveSupport::Callbacks.
|
|
30
30
|
include ActiveSupport::Callbacks
|
|
31
31
|
|
|
32
32
|
included do
|
|
33
33
|
define_callbacks :process_action,
|
|
34
34
|
terminator: ->(controller, result_lambda) { result_lambda.call; controller.performed? },
|
|
35
35
|
skip_after_callbacks_if_terminated: true
|
|
36
|
+
mattr_accessor :raise_on_missing_callback_actions, default: false
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
class ActionFilter # :nodoc:
|
|
39
|
-
def initialize(actions)
|
|
40
|
+
def initialize(filters, conditional_key, actions)
|
|
41
|
+
@filters = filters.to_a
|
|
42
|
+
@conditional_key = conditional_key
|
|
40
43
|
@actions = Array(actions).map(&:to_s).to_set
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
def match?(controller)
|
|
47
|
+
if controller.raise_on_missing_callback_actions
|
|
48
|
+
missing_action = @actions.find { |action| !controller.available_action?(action) }
|
|
49
|
+
if missing_action
|
|
50
|
+
filter_names = @filters.length == 1 ? @filters.first.inspect : @filters.inspect
|
|
51
|
+
|
|
52
|
+
message = <<~MSG
|
|
53
|
+
The #{missing_action} action could not be found for the #{filter_names}
|
|
54
|
+
callback on #{controller.class.name}, but it is listed in the controller's
|
|
55
|
+
#{@conditional_key.inspect} option.
|
|
56
|
+
|
|
57
|
+
Raising for missing callback actions is a new default in Rails 7.1, if you'd
|
|
58
|
+
like to turn this off you can delete the option from the environment configurations
|
|
59
|
+
or set `config.action_controller.raise_on_missing_callback_actions` to `false`.
|
|
60
|
+
MSG
|
|
61
|
+
|
|
62
|
+
raise ActionNotFound.new(message, controller, missing_action)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
44
66
|
@actions.include?(controller.action_name)
|
|
45
67
|
end
|
|
46
68
|
|
|
@@ -50,53 +72,57 @@ module AbstractController
|
|
|
50
72
|
end
|
|
51
73
|
|
|
52
74
|
module ClassMethods
|
|
53
|
-
# If
|
|
54
|
-
#
|
|
75
|
+
# If `:only` or `:except` are used, convert the options into the `:if` and
|
|
76
|
+
# `:unless` options of ActiveSupport::Callbacks.
|
|
77
|
+
#
|
|
78
|
+
# The basic idea is that `:only => :index` gets converted to `:if => proc {|c|
|
|
79
|
+
# c.action_name == "index" }`.
|
|
55
80
|
#
|
|
56
|
-
#
|
|
57
|
-
# <tt>:if => proc {|c| c.action_name == "index" }</tt>.
|
|
81
|
+
# Note that `:only` has priority over `:if` in case they are used together.
|
|
58
82
|
#
|
|
59
|
-
#
|
|
60
|
-
# are used together.
|
|
83
|
+
# only: :index, if: -> { true } # the :if option will be ignored.
|
|
61
84
|
#
|
|
62
|
-
#
|
|
85
|
+
# Note that `:if` has priority over `:except` in case they are used together.
|
|
63
86
|
#
|
|
64
|
-
#
|
|
65
|
-
# are used together.
|
|
87
|
+
# except: :index, if: -> { true } # the :except option will be ignored.
|
|
66
88
|
#
|
|
67
|
-
#
|
|
89
|
+
# #### Options
|
|
90
|
+
# * `only` - The callback should be run only for this action.
|
|
91
|
+
# * `except` - The callback should be run for all actions except this action.
|
|
68
92
|
#
|
|
69
|
-
# ==== Options
|
|
70
|
-
# * <tt>only</tt> - The callback should be run only for this action.
|
|
71
|
-
# * <tt>except</tt> - The callback should be run for all actions except this action.
|
|
72
93
|
def _normalize_callback_options(options)
|
|
73
94
|
_normalize_callback_option(options, :only, :if)
|
|
74
95
|
_normalize_callback_option(options, :except, :unless)
|
|
75
96
|
end
|
|
76
97
|
|
|
77
98
|
def _normalize_callback_option(options, from, to) # :nodoc:
|
|
78
|
-
if
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
if from_value = options.delete(from)
|
|
100
|
+
filters = options[:filters]
|
|
101
|
+
from_value = ActionFilter.new(filters, from, from_value)
|
|
102
|
+
options[to] = Array(options[to]).unshift(from_value)
|
|
81
103
|
end
|
|
82
104
|
end
|
|
83
105
|
|
|
84
|
-
# Take callback names and an optional callback proc, normalize them,
|
|
85
|
-
#
|
|
86
|
-
#
|
|
106
|
+
# Take callback names and an optional callback proc, normalize them, then call
|
|
107
|
+
# the block with each callback. This allows us to abstract the normalization
|
|
108
|
+
# across several methods that use it.
|
|
109
|
+
#
|
|
110
|
+
# #### Parameters
|
|
111
|
+
# * `callbacks` - An array of callbacks, with an optional options hash as the
|
|
112
|
+
# last parameter.
|
|
113
|
+
# * `block` - A proc that should be added to the callbacks.
|
|
114
|
+
#
|
|
87
115
|
#
|
|
88
|
-
#
|
|
89
|
-
# *
|
|
90
|
-
# options hash
|
|
91
|
-
# * <tt>block</tt> - A proc that should be added to the callbacks.
|
|
116
|
+
# #### Block Parameters
|
|
117
|
+
# * `name` - The callback to be added.
|
|
118
|
+
# * `options` - A hash of options to be used when adding the callback.
|
|
92
119
|
#
|
|
93
|
-
# ==== Block Parameters
|
|
94
|
-
# * <tt>name</tt> - The callback to be added.
|
|
95
|
-
# * <tt>options</tt> - A hash of options to be used when adding the callback.
|
|
96
120
|
def _insert_callbacks(callbacks, block = nil)
|
|
97
121
|
options = callbacks.extract_options!
|
|
98
|
-
_normalize_callback_options(options)
|
|
99
122
|
callbacks.push(block) if block
|
|
123
|
+
options[:filters] = callbacks
|
|
124
|
+
_normalize_callback_options(options)
|
|
125
|
+
options.delete(:filters)
|
|
100
126
|
callbacks.each do |callback|
|
|
101
127
|
yield callback, options
|
|
102
128
|
end
|
|
@@ -109,20 +135,21 @@ module AbstractController
|
|
|
109
135
|
#
|
|
110
136
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
|
111
137
|
#
|
|
112
|
-
# If the callback renders or redirects, the action will not run. If there
|
|
113
|
-
#
|
|
114
|
-
#
|
|
138
|
+
# If the callback renders or redirects, the action will not run. If there are
|
|
139
|
+
# additional callbacks scheduled to run after that callback, they are also
|
|
140
|
+
# cancelled.
|
|
115
141
|
|
|
116
142
|
##
|
|
117
143
|
# :method: prepend_before_action
|
|
118
144
|
#
|
|
119
145
|
# :call-seq: prepend_before_action(names, block)
|
|
120
146
|
#
|
|
121
|
-
# Prepend a callback before actions. See _insert_callbacks for parameter
|
|
147
|
+
# Prepend a callback before actions. See _insert_callbacks for parameter
|
|
148
|
+
# details.
|
|
122
149
|
#
|
|
123
|
-
# If the callback renders or redirects, the action will not run. If there
|
|
124
|
-
#
|
|
125
|
-
#
|
|
150
|
+
# If the callback renders or redirects, the action will not run. If there are
|
|
151
|
+
# additional callbacks scheduled to run after that callback, they are also
|
|
152
|
+
# cancelled.
|
|
126
153
|
|
|
127
154
|
##
|
|
128
155
|
# :method: skip_before_action
|
|
@@ -138,9 +165,9 @@ module AbstractController
|
|
|
138
165
|
#
|
|
139
166
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
|
140
167
|
#
|
|
141
|
-
# If the callback renders or redirects, the action will not run. If there
|
|
142
|
-
#
|
|
143
|
-
#
|
|
168
|
+
# If the callback renders or redirects, the action will not run. If there are
|
|
169
|
+
# additional callbacks scheduled to run after that callback, they are also
|
|
170
|
+
# cancelled.
|
|
144
171
|
|
|
145
172
|
##
|
|
146
173
|
# :method: after_action
|
|
@@ -182,7 +209,8 @@ module AbstractController
|
|
|
182
209
|
#
|
|
183
210
|
# :call-seq: prepend_around_action(names, block)
|
|
184
211
|
#
|
|
185
|
-
# Prepend a callback around actions. See _insert_callbacks for parameter
|
|
212
|
+
# Prepend a callback around actions. See _insert_callbacks for parameter
|
|
213
|
+
# details.
|
|
186
214
|
|
|
187
215
|
##
|
|
188
216
|
# :method: skip_around_action
|
|
@@ -197,9 +225,8 @@ module AbstractController
|
|
|
197
225
|
# :call-seq: append_around_action(names, block)
|
|
198
226
|
#
|
|
199
227
|
# Append a callback around actions. See _insert_callbacks for parameter details.
|
|
200
|
-
|
|
201
|
-
#
|
|
202
|
-
# for each of before, after, and around.
|
|
228
|
+
# set up before_action, prepend_before_action, skip_before_action, etc. for each
|
|
229
|
+
# of before, after, and around.
|
|
203
230
|
[:before, :after, :around].each do |callback|
|
|
204
231
|
define_method "#{callback}_action" do |*names, &blk|
|
|
205
232
|
_insert_callbacks(names, blk) do |name, options|
|
|
@@ -213,8 +240,8 @@ module AbstractController
|
|
|
213
240
|
end
|
|
214
241
|
end
|
|
215
242
|
|
|
216
|
-
# Skip a before, after or around callback. See _insert_callbacks
|
|
217
|
-
#
|
|
243
|
+
# Skip a before, after or around callback. See _insert_callbacks for details on
|
|
244
|
+
# the allowed parameters.
|
|
218
245
|
define_method "skip_#{callback}_action" do |*names|
|
|
219
246
|
_insert_callbacks(names) do |name, options|
|
|
220
247
|
skip_callback(:process_action, callback, name, options)
|
|
@@ -227,8 +254,8 @@ module AbstractController
|
|
|
227
254
|
end
|
|
228
255
|
|
|
229
256
|
private
|
|
230
|
-
# Override
|
|
231
|
-
#
|
|
257
|
+
# Override `AbstractController::Base#process_action` to run the `process_action`
|
|
258
|
+
# callbacks around the normal behavior.
|
|
232
259
|
def process_action(...)
|
|
233
260
|
run_callbacks(:process_action) do
|
|
234
261
|
super
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "action_dispatch/http/mime_type"
|
|
4
6
|
|
|
5
7
|
module AbstractController
|
|
@@ -7,10 +9,9 @@ module AbstractController
|
|
|
7
9
|
def self.generate_method_for_mime(mime)
|
|
8
10
|
sym = mime.is_a?(Symbol) ? mime : mime.to_sym
|
|
9
11
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
10
|
-
def #{sym}(
|
|
11
|
-
custom(Mime[:#{sym}],
|
|
12
|
+
def #{sym}(...)
|
|
13
|
+
custom(Mime[:#{sym}], ...)
|
|
12
14
|
end
|
|
13
|
-
ruby2_keywords(:#{sym})
|
|
14
15
|
RUBY
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -23,7 +24,7 @@ module AbstractController
|
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
private
|
|
26
|
-
def method_missing(symbol,
|
|
27
|
+
def method_missing(symbol, ...)
|
|
27
28
|
unless mime_constant = Mime[symbol]
|
|
28
29
|
raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
|
|
29
30
|
"https://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. " \
|
|
@@ -34,11 +35,10 @@ module AbstractController
|
|
|
34
35
|
|
|
35
36
|
if Mime::SET.include?(mime_constant)
|
|
36
37
|
AbstractController::Collector.generate_method_for_mime(mime_constant)
|
|
37
|
-
public_send(symbol,
|
|
38
|
+
public_send(symbol, ...)
|
|
38
39
|
else
|
|
39
40
|
super
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
|
-
ruby2_keywords(:method_missing)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/dependencies"
|
|
4
6
|
require "active_support/core_ext/name_error"
|
|
5
7
|
|
|
@@ -10,8 +12,8 @@ module AbstractController
|
|
|
10
12
|
included do
|
|
11
13
|
class_attribute :_helper_methods, default: Array.new
|
|
12
14
|
|
|
13
|
-
# This is here so that it is always higher in the inheritance chain than
|
|
14
|
-
#
|
|
15
|
+
# This is here so that it is always higher in the inheritance chain than the
|
|
16
|
+
# definition in lib/action_view/rendering.rb
|
|
15
17
|
redefine_singleton_method(:_helpers) do
|
|
16
18
|
if @_helpers ||= nil
|
|
17
19
|
@_helpers
|
|
@@ -23,28 +25,46 @@ module AbstractController
|
|
|
23
25
|
self._helpers = define_helpers_module(self)
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@path = "helpers/#{path}.rb"
|
|
30
|
-
set_backtrace error.backtrace
|
|
28
|
+
def _helpers
|
|
29
|
+
self.class._helpers
|
|
30
|
+
end
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
module Resolution # :nodoc:
|
|
33
|
+
def modules_for_helpers(modules_or_helper_prefixes)
|
|
34
|
+
modules_or_helper_prefixes.flatten.map! do |module_or_helper_prefix|
|
|
35
|
+
case module_or_helper_prefix
|
|
36
|
+
when Module
|
|
37
|
+
module_or_helper_prefix
|
|
38
|
+
when String, Symbol
|
|
39
|
+
helper_prefix = module_or_helper_prefix.to_s
|
|
40
|
+
helper_prefix = helper_prefix.camelize unless helper_prefix.start_with?(/[A-Z]/)
|
|
41
|
+
"#{helper_prefix}Helper".constantize
|
|
42
|
+
else
|
|
43
|
+
raise ArgumentError, "helper must be a String, Symbol, or Module"
|
|
44
|
+
end
|
|
36
45
|
end
|
|
37
46
|
end
|
|
38
|
-
end
|
|
39
47
|
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
def all_helpers_from_path(path)
|
|
49
|
+
helpers = Array(path).flat_map do |_path|
|
|
50
|
+
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file[_path.to_s.size + 1..-"_helper.rb".size - 1] }
|
|
51
|
+
names.sort!
|
|
52
|
+
end
|
|
53
|
+
helpers.uniq!
|
|
54
|
+
helpers
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def helper_modules_from_paths(paths)
|
|
58
|
+
modules_for_helpers(all_helpers_from_path(paths))
|
|
59
|
+
end
|
|
42
60
|
end
|
|
43
61
|
|
|
62
|
+
extend Resolution
|
|
63
|
+
|
|
44
64
|
module ClassMethods
|
|
45
|
-
# When a class is inherited, wrap its helper module in a new module.
|
|
46
|
-
#
|
|
47
|
-
#
|
|
65
|
+
# When a class is inherited, wrap its helper module in a new module. This
|
|
66
|
+
# ensures that the parent class's module can be changed independently of the
|
|
67
|
+
# child class's.
|
|
48
68
|
def inherited(klass)
|
|
49
69
|
# Inherited from parent by default
|
|
50
70
|
klass._helpers = nil
|
|
@@ -55,28 +75,54 @@ module AbstractController
|
|
|
55
75
|
|
|
56
76
|
attr_writer :_helpers
|
|
57
77
|
|
|
78
|
+
include Resolution
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
# :method: modules_for_helpers
|
|
82
|
+
# :call-seq: modules_for_helpers(modules_or_helper_prefixes)
|
|
83
|
+
#
|
|
84
|
+
# Given an array of values like the ones accepted by `helper`, this method
|
|
85
|
+
# returns an array with the corresponding modules, in the same order.
|
|
86
|
+
#
|
|
87
|
+
# ActionController::Base.modules_for_helpers(["application", "chart", "rubygems"])
|
|
88
|
+
# # => [ApplicationHelper, ChartHelper, RubygemsHelper]
|
|
89
|
+
#
|
|
90
|
+
#--
|
|
91
|
+
# Implemented by Resolution#modules_for_helpers.
|
|
92
|
+
|
|
93
|
+
# :method: # all_helpers_from_path
|
|
94
|
+
# :call-seq: all_helpers_from_path(path)
|
|
95
|
+
#
|
|
96
|
+
# Returns a list of helper names in a given path.
|
|
97
|
+
#
|
|
98
|
+
# ActionController::Base.all_helpers_from_path 'app/helpers'
|
|
99
|
+
# # => ["application", "chart", "rubygems"]
|
|
100
|
+
#
|
|
101
|
+
#--
|
|
102
|
+
# Implemented by Resolution#all_helpers_from_path.
|
|
103
|
+
|
|
58
104
|
# Declare a controller method as a helper. For example, the following
|
|
59
|
-
# makes the
|
|
105
|
+
# makes the `current_user` and `logged_in?` controller methods available
|
|
60
106
|
# to the view:
|
|
61
|
-
#
|
|
62
|
-
#
|
|
107
|
+
# class ApplicationController < ActionController::Base
|
|
108
|
+
# helper_method :current_user, :logged_in?
|
|
63
109
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
110
|
+
# private
|
|
111
|
+
# def current_user
|
|
112
|
+
# @current_user ||= User.find_by(id: session[:user])
|
|
113
|
+
# end
|
|
68
114
|
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
115
|
+
# def logged_in?
|
|
116
|
+
# current_user != nil
|
|
117
|
+
# end
|
|
118
|
+
# end
|
|
73
119
|
#
|
|
74
120
|
# In a view:
|
|
75
|
-
#
|
|
121
|
+
# <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
|
|
76
122
|
#
|
|
77
|
-
#
|
|
78
|
-
# *
|
|
79
|
-
#
|
|
123
|
+
# #### Parameters
|
|
124
|
+
# * `method[, method]` - A name or names of a method on the controller to be
|
|
125
|
+
# made available on the view.
|
|
80
126
|
def helper_method(*methods)
|
|
81
127
|
methods.flatten!
|
|
82
128
|
self._helper_methods += methods
|
|
@@ -85,68 +131,67 @@ module AbstractController
|
|
|
85
131
|
file, line = location.path, location.lineno
|
|
86
132
|
|
|
87
133
|
methods.each do |method|
|
|
88
|
-
# def current_user(
|
|
89
|
-
# controller.send(:'current_user',
|
|
134
|
+
# def current_user(...)
|
|
135
|
+
# controller.send(:'current_user', ...)
|
|
90
136
|
# end
|
|
91
137
|
_helpers_for_modification.class_eval <<~ruby_eval.lines.map(&:strip).join(";"), file, line
|
|
92
|
-
def #{method}(
|
|
93
|
-
controller.send(:'#{method}',
|
|
138
|
+
def #{method}(...)
|
|
139
|
+
controller.send(:'#{method}', ...)
|
|
94
140
|
end
|
|
95
|
-
ruby2_keywords(:'#{method}')
|
|
96
141
|
ruby_eval
|
|
97
142
|
end
|
|
98
143
|
end
|
|
99
144
|
|
|
100
145
|
# Includes the given modules in the template class.
|
|
101
146
|
#
|
|
102
|
-
# Modules can be specified in different ways. All of the following calls
|
|
103
|
-
#
|
|
147
|
+
# Modules can be specified in different ways. All of the following calls include
|
|
148
|
+
# `FooHelper`:
|
|
104
149
|
#
|
|
105
|
-
#
|
|
106
|
-
#
|
|
150
|
+
# # Module, recommended.
|
|
151
|
+
# helper FooHelper
|
|
107
152
|
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
#
|
|
153
|
+
# # String/symbol without the "helper" suffix, camel or snake case.
|
|
154
|
+
# helper "Foo"
|
|
155
|
+
# helper :Foo
|
|
156
|
+
# helper "foo"
|
|
157
|
+
# helper :foo
|
|
113
158
|
#
|
|
114
|
-
# The last two assume that
|
|
159
|
+
# The last two assume that `"foo".camelize` returns "Foo".
|
|
115
160
|
#
|
|
116
|
-
# When strings or symbols are passed, the method finds the actual module
|
|
117
|
-
#
|
|
118
|
-
#
|
|
161
|
+
# When strings or symbols are passed, the method finds the actual module object
|
|
162
|
+
# using String#constantize. Therefore, if the module has not been yet loaded, it
|
|
163
|
+
# has to be autoloadable, which is normally the case.
|
|
119
164
|
#
|
|
120
|
-
# Namespaces are supported. The following calls include
|
|
165
|
+
# Namespaces are supported. The following calls include `Foo::BarHelper`:
|
|
121
166
|
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
167
|
+
# # Module, recommended.
|
|
168
|
+
# helper Foo::BarHelper
|
|
124
169
|
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
170
|
+
# # String/symbol without the "helper" suffix, camel or snake case.
|
|
171
|
+
# helper "Foo::Bar"
|
|
172
|
+
# helper :"Foo::Bar"
|
|
173
|
+
# helper "foo/bar"
|
|
174
|
+
# helper :"foo/bar"
|
|
130
175
|
#
|
|
131
|
-
# The last two assume that
|
|
176
|
+
# The last two assume that `"foo/bar".camelize` returns "Foo::Bar".
|
|
132
177
|
#
|
|
133
|
-
# The method accepts a block too. If present, the block is evaluated in
|
|
134
|
-
#
|
|
135
|
-
#
|
|
178
|
+
# The method accepts a block too. If present, the block is evaluated in the
|
|
179
|
+
# context of the controller helper module. This simple call makes the `wadus`
|
|
180
|
+
# method available in templates of the enclosing controller:
|
|
136
181
|
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
182
|
+
# helper do
|
|
183
|
+
# def wadus
|
|
184
|
+
# "wadus"
|
|
185
|
+
# end
|
|
140
186
|
# end
|
|
141
|
-
# end
|
|
142
187
|
#
|
|
143
188
|
# Furthermore, all the above styles can be mixed together:
|
|
144
189
|
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
#
|
|
190
|
+
# helper FooHelper, "woo", "bar/baz" do
|
|
191
|
+
# def wadus
|
|
192
|
+
# "wadus"
|
|
193
|
+
# end
|
|
148
194
|
# end
|
|
149
|
-
# end
|
|
150
195
|
#
|
|
151
196
|
def helper(*args, &block)
|
|
152
197
|
modules_for_helpers(args).each do |mod|
|
|
@@ -157,8 +202,8 @@ module AbstractController
|
|
|
157
202
|
_helpers_for_modification.module_eval(&block) if block_given?
|
|
158
203
|
end
|
|
159
204
|
|
|
160
|
-
# Clears up all existing helpers in this class, only keeping the helper
|
|
161
|
-
#
|
|
205
|
+
# Clears up all existing helpers in this class, only keeping the helper with the
|
|
206
|
+
# same name as this class.
|
|
162
207
|
def clear_helpers
|
|
163
208
|
inherited_helper_methods = _helper_methods
|
|
164
209
|
self._helpers = Module.new
|
|
@@ -168,23 +213,6 @@ module AbstractController
|
|
|
168
213
|
default_helper_module! unless anonymous?
|
|
169
214
|
end
|
|
170
215
|
|
|
171
|
-
# Given an array of values like the ones accepted by +helper+, this method
|
|
172
|
-
# returns an array with the corresponding modules, in the same order.
|
|
173
|
-
def modules_for_helpers(modules_or_helper_prefixes)
|
|
174
|
-
modules_or_helper_prefixes.flatten.map! do |module_or_helper_prefix|
|
|
175
|
-
case module_or_helper_prefix
|
|
176
|
-
when Module
|
|
177
|
-
module_or_helper_prefix
|
|
178
|
-
when String, Symbol
|
|
179
|
-
helper_prefix = module_or_helper_prefix.to_s
|
|
180
|
-
helper_prefix = helper_prefix.camelize unless helper_prefix.start_with?(/[A-Z]/)
|
|
181
|
-
"#{helper_prefix}Helper".constantize
|
|
182
|
-
else
|
|
183
|
-
raise ArgumentError, "helper must be a String, Symbol, or Module"
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
216
|
def _helpers_for_modification
|
|
189
217
|
unless @_helpers
|
|
190
218
|
self._helpers = define_helpers_module(self, superclass._helpers)
|
|
@@ -194,8 +222,8 @@ module AbstractController
|
|
|
194
222
|
|
|
195
223
|
private
|
|
196
224
|
def define_helpers_module(klass, helpers = nil)
|
|
197
|
-
# In some tests inherited is called explicitly. In that case, just
|
|
198
|
-
#
|
|
225
|
+
# In some tests inherited is called explicitly. In that case, just return the
|
|
226
|
+
# module from the first time it was defined
|
|
199
227
|
return klass.const_get(:HelperMethods) if klass.const_defined?(:HelperMethods, false)
|
|
200
228
|
|
|
201
229
|
mod = Module.new
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/module/introspection"
|
|
4
6
|
|
|
5
7
|
module AbstractController
|
|
@@ -10,26 +12,11 @@ module AbstractController
|
|
|
10
12
|
define_method(:inherited) do |klass|
|
|
11
13
|
super(klass)
|
|
12
14
|
|
|
13
|
-
namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
|
|
14
|
-
actual_routes = namespace ? namespace.railtie_routes_url_helpers._routes : routes
|
|
15
|
-
|
|
16
|
-
if namespace
|
|
15
|
+
if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
|
|
17
16
|
klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
|
|
18
17
|
else
|
|
19
18
|
klass.include(routes.url_helpers(include_path_helpers))
|
|
20
19
|
end
|
|
21
|
-
|
|
22
|
-
# In the case that we have ex.
|
|
23
|
-
# class A::Foo < ApplicationController
|
|
24
|
-
# class Bar < A::Foo
|
|
25
|
-
# We will need to redefine _routes because it will not be correct
|
|
26
|
-
# via inheritance.
|
|
27
|
-
unless klass._routes.equal?(actual_routes)
|
|
28
|
-
klass.redefine_singleton_method(:_routes) { actual_routes }
|
|
29
|
-
klass.include(Module.new do
|
|
30
|
-
define_method(:_routes) { @_routes || actual_routes }
|
|
31
|
-
end)
|
|
32
|
-
end
|
|
33
20
|
end
|
|
34
21
|
end
|
|
35
22
|
end
|