actionpack 7.0.8.7 → 7.2.2.1
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 +90 -537
- 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 +121 -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 +12 -30
- 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 +78 -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 +187 -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 +212 -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 +125 -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 +157 -128
- 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 +48 -45
- data/lib/action_dispatch/http/filter_parameters.rb +18 -8
- data/lib/action_dispatch/http/filter_redirect.rb +22 -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 -27
- data/lib/action_dispatch/http/rack_cache.rb +4 -0
- data/lib/action_dispatch/http/request.rb +132 -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 +88 -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 +686 -639
- 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 +106 -62
- 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 +52 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +18 -17
- metadata +86 -27
@@ -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,56 @@ 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
|
-
# class ApplicationController < ActionController::Base
|
62
|
-
# helper_method :current_user, :logged_in?
|
63
107
|
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# @current_user ||= User.find_by(id: session[:user])
|
67
|
-
# end
|
108
|
+
# class ApplicationController < ActionController::Base
|
109
|
+
# helper_method :current_user, :logged_in?
|
68
110
|
#
|
69
|
-
#
|
70
|
-
# current_user
|
71
|
-
#
|
72
|
-
#
|
111
|
+
# private
|
112
|
+
# def current_user
|
113
|
+
# @current_user ||= User.find_by(id: session[:user])
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# def logged_in?
|
117
|
+
# current_user != nil
|
118
|
+
# end
|
119
|
+
# end
|
73
120
|
#
|
74
121
|
# In a view:
|
75
|
-
# <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
|
76
122
|
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
123
|
+
# <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
|
124
|
+
#
|
125
|
+
# #### Parameters
|
126
|
+
# * `method[, method]` - A name or names of a method on the controller to be
|
127
|
+
# made available on the view.
|
80
128
|
def helper_method(*methods)
|
81
129
|
methods.flatten!
|
82
130
|
self._helper_methods += methods
|
@@ -85,68 +133,67 @@ module AbstractController
|
|
85
133
|
file, line = location.path, location.lineno
|
86
134
|
|
87
135
|
methods.each do |method|
|
88
|
-
# def current_user(
|
89
|
-
# controller.send(:'current_user',
|
136
|
+
# def current_user(...)
|
137
|
+
# controller.send(:'current_user', ...)
|
90
138
|
# end
|
91
139
|
_helpers_for_modification.class_eval <<~ruby_eval.lines.map(&:strip).join(";"), file, line
|
92
|
-
def #{method}(
|
93
|
-
controller.send(:'#{method}',
|
140
|
+
def #{method}(...)
|
141
|
+
controller.send(:'#{method}', ...)
|
94
142
|
end
|
95
|
-
ruby2_keywords(:'#{method}')
|
96
143
|
ruby_eval
|
97
144
|
end
|
98
145
|
end
|
99
146
|
|
100
147
|
# Includes the given modules in the template class.
|
101
148
|
#
|
102
|
-
# Modules can be specified in different ways. All of the following calls
|
103
|
-
#
|
149
|
+
# Modules can be specified in different ways. All of the following calls include
|
150
|
+
# `FooHelper`:
|
104
151
|
#
|
105
|
-
#
|
106
|
-
#
|
152
|
+
# # Module, recommended.
|
153
|
+
# helper FooHelper
|
107
154
|
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
155
|
+
# # String/symbol without the "helper" suffix, camel or snake case.
|
156
|
+
# helper "Foo"
|
157
|
+
# helper :Foo
|
158
|
+
# helper "foo"
|
159
|
+
# helper :foo
|
113
160
|
#
|
114
|
-
# The last two assume that
|
161
|
+
# The last two assume that `"foo".camelize` returns "Foo".
|
115
162
|
#
|
116
|
-
# When strings or symbols are passed, the method finds the actual module
|
117
|
-
#
|
118
|
-
#
|
163
|
+
# When strings or symbols are passed, the method finds the actual module object
|
164
|
+
# using String#constantize. Therefore, if the module has not been yet loaded, it
|
165
|
+
# has to be autoloadable, which is normally the case.
|
119
166
|
#
|
120
|
-
# Namespaces are supported. The following calls include
|
167
|
+
# Namespaces are supported. The following calls include `Foo::BarHelper`:
|
121
168
|
#
|
122
|
-
#
|
123
|
-
#
|
169
|
+
# # Module, recommended.
|
170
|
+
# helper Foo::BarHelper
|
124
171
|
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
172
|
+
# # String/symbol without the "helper" suffix, camel or snake case.
|
173
|
+
# helper "Foo::Bar"
|
174
|
+
# helper :"Foo::Bar"
|
175
|
+
# helper "foo/bar"
|
176
|
+
# helper :"foo/bar"
|
130
177
|
#
|
131
|
-
# The last two assume that
|
178
|
+
# The last two assume that `"foo/bar".camelize` returns "Foo::Bar".
|
132
179
|
#
|
133
|
-
# The method accepts a block too. If present, the block is evaluated in
|
134
|
-
#
|
135
|
-
#
|
180
|
+
# The method accepts a block too. If present, the block is evaluated in the
|
181
|
+
# context of the controller helper module. This simple call makes the `wadus`
|
182
|
+
# method available in templates of the enclosing controller:
|
136
183
|
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
184
|
+
# helper do
|
185
|
+
# def wadus
|
186
|
+
# "wadus"
|
187
|
+
# end
|
140
188
|
# end
|
141
|
-
# end
|
142
189
|
#
|
143
190
|
# Furthermore, all the above styles can be mixed together:
|
144
191
|
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
192
|
+
# helper FooHelper, "woo", "bar/baz" do
|
193
|
+
# def wadus
|
194
|
+
# "wadus"
|
195
|
+
# end
|
148
196
|
# end
|
149
|
-
# end
|
150
197
|
#
|
151
198
|
def helper(*args, &block)
|
152
199
|
modules_for_helpers(args).each do |mod|
|
@@ -157,8 +204,8 @@ module AbstractController
|
|
157
204
|
_helpers_for_modification.module_eval(&block) if block_given?
|
158
205
|
end
|
159
206
|
|
160
|
-
# Clears up all existing helpers in this class, only keeping the helper
|
161
|
-
#
|
207
|
+
# Clears up all existing helpers in this class, only keeping the helper with the
|
208
|
+
# same name as this class.
|
162
209
|
def clear_helpers
|
163
210
|
inherited_helper_methods = _helper_methods
|
164
211
|
self._helpers = Module.new
|
@@ -168,23 +215,6 @@ module AbstractController
|
|
168
215
|
default_helper_module! unless anonymous?
|
169
216
|
end
|
170
217
|
|
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
218
|
def _helpers_for_modification
|
189
219
|
unless @_helpers
|
190
220
|
self._helpers = define_helpers_module(self, superclass._helpers)
|
@@ -194,8 +224,8 @@ module AbstractController
|
|
194
224
|
|
195
225
|
private
|
196
226
|
def define_helpers_module(klass, helpers = nil)
|
197
|
-
# In some tests inherited is called explicitly. In that case, just
|
198
|
-
#
|
227
|
+
# In some tests inherited is called explicitly. In that case, just return the
|
228
|
+
# module from the first time it was defined
|
199
229
|
return klass.const_get(:HelperMethods) if klass.const_defined?(:HelperMethods, false)
|
200
230
|
|
201
231
|
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
|