actionpack 7.1.5.1 → 8.1.2
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 +308 -523
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +6 -2
- data/lib/abstract_controller/base.rb +104 -105
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +8 -3
- data/lib/abstract_controller/callbacks.rb +70 -62
- data/lib/abstract_controller/collector.rb +7 -7
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +71 -84
- data/lib/abstract_controller/logger.rb +4 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -13
- data/lib/abstract_controller/translation.rb +12 -13
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +76 -72
- data/lib/action_controller/base.rb +199 -126
- data/lib/action_controller/caching.rb +16 -14
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +21 -18
- data/lib/action_controller/log_subscriber.rb +23 -2
- data/lib/action_controller/metal/allow_browser.rb +133 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +217 -175
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +72 -63
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +16 -9
- data/lib/action_controller/metal/flash.rb +13 -14
- data/lib/action_controller/metal/head.rb +15 -11
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +16 -14
- data/lib/action_controller/metal/live.rb +177 -128
- 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 +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +22 -12
- data/lib/action_controller/metal/rate_limiting.rb +92 -0
- data/lib/action_controller/metal/redirecting.rb +213 -94
- data/lib/action_controller/metal/renderers.rb +78 -57
- data/lib/action_controller/metal/rendering.rb +111 -77
- data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
- data/lib/action_controller/metal/rescue.rb +20 -9
- data/lib/action_controller/metal/streaming.rb +118 -195
- data/lib/action_controller/metal/strong_parameters.rb +720 -530
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +36 -15
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +160 -131
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +163 -35
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +54 -39
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +3 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +14 -12
- data/lib/action_dispatch/http/permissions_policy.rb +25 -36
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +141 -92
- data/lib/action_dispatch/http/response.rb +137 -77
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +187 -89
- data/lib/action_dispatch/journey/formatter.rb +21 -9
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
- data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +8 -6
- data/lib/action_dispatch/journey/parser.rb +99 -195
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +54 -38
- data/lib/action_dispatch/journey/router/utils.rb +22 -27
- data/lib/action_dispatch/journey/router.rb +63 -83
- data/lib/action_dispatch/journey/routes.rb +11 -2
- data/lib/action_dispatch/journey/scanner.rb +46 -42
- data/lib/action_dispatch/journey/visitors.rb +57 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +7 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +125 -106
- data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +13 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
- data/lib/action_dispatch/middleware/executor.rb +19 -4
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
- data/lib/action_dispatch/middleware/request_id.rb +16 -10
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +53 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +23 -3
- data/lib/action_dispatch/request/session.rb +24 -21
- data/lib/action_dispatch/request/utils.rb +11 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +85 -60
- data/lib/action_dispatch/routing/mapper.rb +1031 -851
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +47 -39
- data/lib/action_dispatch/routing/route_set.rb +79 -56
- data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +16 -23
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
- 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 +52 -25
- data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +233 -223
- data/lib/action_dispatch/testing/request_encoder.rb +11 -9
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +11 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +36 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +36 -32
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -31
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/hash/indifferent_access"
|
|
4
6
|
|
|
5
7
|
module ActionDispatch
|
|
@@ -81,8 +83,8 @@ module ActionDispatch
|
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
class CustomParamEncoder # :nodoc:
|
|
84
|
-
def self.
|
|
85
|
-
return params unless
|
|
86
|
+
def self.encode_for_template(params, encoding_template)
|
|
87
|
+
return params unless encoding_template
|
|
86
88
|
params.except(:controller, :action).each do |key, value|
|
|
87
89
|
ActionDispatch::Request::Utils.each_param_value(value) do |param|
|
|
88
90
|
# If `param` is frozen, it comes from the router defaults
|
|
@@ -96,8 +98,14 @@ module ActionDispatch
|
|
|
96
98
|
params
|
|
97
99
|
end
|
|
98
100
|
|
|
101
|
+
def self.encode(request, params, controller, action)
|
|
102
|
+
encoding_template = action_encoding_template(request, controller, action)
|
|
103
|
+
encode_for_template(params, encoding_template)
|
|
104
|
+
end
|
|
105
|
+
|
|
99
106
|
def self.action_encoding_template(request, controller, action) # :nodoc:
|
|
100
|
-
|
|
107
|
+
controller && controller.valid_encoding? &&
|
|
108
|
+
request.controller_class_for(controller).action_encoding_template(action)
|
|
101
109
|
rescue MissingController
|
|
102
110
|
nil
|
|
103
111
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "delegate"
|
|
4
6
|
require "io/console/size"
|
|
5
7
|
|
|
@@ -62,44 +64,73 @@ module ActionDispatch
|
|
|
62
64
|
def engine?
|
|
63
65
|
app.engine?
|
|
64
66
|
end
|
|
67
|
+
|
|
68
|
+
def to_h
|
|
69
|
+
{ name: name,
|
|
70
|
+
verb: verb,
|
|
71
|
+
path: path,
|
|
72
|
+
reqs: reqs,
|
|
73
|
+
source_location: source_location }
|
|
74
|
+
end
|
|
65
75
|
end
|
|
66
76
|
|
|
67
77
|
##
|
|
68
78
|
# This class is just used for displaying route information when someone
|
|
69
|
-
# executes `bin/rails routes` or looks at the RoutingError page.
|
|
70
|
-
#
|
|
79
|
+
# executes `bin/rails routes` or looks at the RoutingError page. People should
|
|
80
|
+
# not use this class.
|
|
71
81
|
class RoutesInspector # :nodoc:
|
|
72
82
|
def initialize(routes)
|
|
73
|
-
@
|
|
74
|
-
@
|
|
83
|
+
@routes = wrap_routes(routes)
|
|
84
|
+
@engines = load_engines_routes
|
|
75
85
|
end
|
|
76
86
|
|
|
77
87
|
def format(formatter, filter = {})
|
|
78
|
-
|
|
79
|
-
routes = collect_routes(routes_to_display)
|
|
80
|
-
if routes.none?
|
|
81
|
-
formatter.no_routes(collect_routes(@routes), filter)
|
|
82
|
-
return formatter.result
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
formatter.header routes
|
|
86
|
-
formatter.section routes
|
|
88
|
+
all_routes = { nil => @routes }.merge(@engines)
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
formatter
|
|
90
|
-
formatter.section engine_routes
|
|
90
|
+
all_routes.each do |engine_name, routes|
|
|
91
|
+
format_routes(formatter, filter, engine_name, routes)
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
formatter.result
|
|
94
95
|
end
|
|
95
96
|
|
|
96
97
|
private
|
|
98
|
+
def format_routes(formatter, filter, engine_name, routes)
|
|
99
|
+
routes = filter_routes(routes, normalize_filter(filter)).map(&:to_h)
|
|
100
|
+
|
|
101
|
+
formatter.section_title "Routes for #{engine_name || "application"}" if @engines.any?
|
|
102
|
+
if routes.any?
|
|
103
|
+
formatter.header routes
|
|
104
|
+
formatter.section routes
|
|
105
|
+
else
|
|
106
|
+
formatter.no_routes engine_name, routes, filter
|
|
107
|
+
end
|
|
108
|
+
formatter.footer routes
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def wrap_routes(routes)
|
|
112
|
+
routes.routes.map { |route| RouteWrapper.new(route) }.reject(&:internal?)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def load_engines_routes
|
|
116
|
+
engine_routes = @routes.select(&:engine?)
|
|
117
|
+
|
|
118
|
+
engines = engine_routes.to_h do |engine_route|
|
|
119
|
+
engine_app_routes = engine_route.rack_app.routes
|
|
120
|
+
engine_app_routes = engine_app_routes.routes if engine_app_routes.is_a?(ActionDispatch::Routing::RouteSet)
|
|
121
|
+
|
|
122
|
+
[engine_route.endpoint, wrap_routes(engine_app_routes)]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
engines
|
|
126
|
+
end
|
|
127
|
+
|
|
97
128
|
def normalize_filter(filter)
|
|
98
129
|
if filter[:controller]
|
|
99
130
|
{ controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
|
|
100
131
|
elsif filter[:grep]
|
|
101
132
|
grep_pattern = Regexp.new(filter[:grep])
|
|
102
|
-
path = RFC2396_PARSER.escape(filter[:grep])
|
|
133
|
+
path = URI::RFC2396_PARSER.escape(filter[:grep])
|
|
103
134
|
normalized_path = ("/" + path).squeeze("/")
|
|
104
135
|
|
|
105
136
|
{
|
|
@@ -113,39 +144,13 @@ module ActionDispatch
|
|
|
113
144
|
end
|
|
114
145
|
end
|
|
115
146
|
|
|
116
|
-
def filter_routes(filter)
|
|
147
|
+
def filter_routes(routes, filter)
|
|
117
148
|
if filter
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
filter.any? { |filter_type, value| route_wrapper.matches_filter?(filter_type, value) }
|
|
149
|
+
routes.select do |route|
|
|
150
|
+
filter.any? { |filter_type, value| route.matches_filter?(filter_type, value) }
|
|
121
151
|
end
|
|
122
152
|
else
|
|
123
|
-
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def collect_routes(routes)
|
|
128
|
-
routes.collect do |route|
|
|
129
|
-
RouteWrapper.new(route)
|
|
130
|
-
end.reject(&:internal?).collect do |route|
|
|
131
|
-
collect_engine_routes(route)
|
|
132
|
-
|
|
133
|
-
{ name: route.name,
|
|
134
|
-
verb: route.verb,
|
|
135
|
-
path: route.path,
|
|
136
|
-
reqs: route.reqs,
|
|
137
|
-
source_location: route.source_location }
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def collect_engine_routes(route)
|
|
142
|
-
name = route.endpoint
|
|
143
|
-
return unless route.engine?
|
|
144
|
-
return if @engines[name]
|
|
145
|
-
|
|
146
|
-
routes = route.rack_app.routes
|
|
147
|
-
if routes.is_a?(ActionDispatch::Routing::RouteSet)
|
|
148
|
-
@engines[name] = collect_routes(routes.routes)
|
|
153
|
+
routes
|
|
149
154
|
end
|
|
150
155
|
end
|
|
151
156
|
end
|
|
@@ -169,27 +174,36 @@ module ActionDispatch
|
|
|
169
174
|
def header(routes)
|
|
170
175
|
end
|
|
171
176
|
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
if routes.none?
|
|
175
|
-
<<~MESSAGE
|
|
176
|
-
You don't have any routes defined!
|
|
177
|
+
def footer(routes)
|
|
178
|
+
end
|
|
177
179
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
def no_routes(engine, routes, filter)
|
|
181
|
+
@buffer <<
|
|
182
|
+
if filter.key?(:controller)
|
|
181
183
|
"No routes were found for this controller."
|
|
182
184
|
elsif filter.key?(:grep)
|
|
183
185
|
"No routes were found for this grep pattern."
|
|
186
|
+
elsif routes.none?
|
|
187
|
+
if engine
|
|
188
|
+
"No routes defined."
|
|
189
|
+
else
|
|
190
|
+
<<~MESSAGE
|
|
191
|
+
You don't have any routes defined!
|
|
192
|
+
|
|
193
|
+
Please add some routes in config/routes.rb.
|
|
194
|
+
MESSAGE
|
|
195
|
+
end
|
|
184
196
|
end
|
|
185
197
|
|
|
186
|
-
|
|
198
|
+
unless engine
|
|
199
|
+
@buffer << "For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
|
|
200
|
+
end
|
|
187
201
|
end
|
|
188
202
|
end
|
|
189
203
|
|
|
190
204
|
class Sheet < Base
|
|
191
205
|
def section_title(title)
|
|
192
|
-
@buffer << "
|
|
206
|
+
@buffer << "#{title}:"
|
|
193
207
|
end
|
|
194
208
|
|
|
195
209
|
def section(routes)
|
|
@@ -200,6 +214,10 @@ module ActionDispatch
|
|
|
200
214
|
@buffer << draw_header(routes)
|
|
201
215
|
end
|
|
202
216
|
|
|
217
|
+
def footer(routes)
|
|
218
|
+
@buffer << ""
|
|
219
|
+
end
|
|
220
|
+
|
|
203
221
|
private
|
|
204
222
|
def draw_section(routes)
|
|
205
223
|
header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
|
|
@@ -230,13 +248,17 @@ module ActionDispatch
|
|
|
230
248
|
end
|
|
231
249
|
|
|
232
250
|
def section_title(title)
|
|
233
|
-
@buffer << "
|
|
251
|
+
@buffer << "#{"[ #{title} ]"}"
|
|
234
252
|
end
|
|
235
253
|
|
|
236
254
|
def section(routes)
|
|
237
255
|
@buffer << draw_expanded_section(routes)
|
|
238
256
|
end
|
|
239
257
|
|
|
258
|
+
def footer(routes)
|
|
259
|
+
@buffer << ""
|
|
260
|
+
end
|
|
261
|
+
|
|
240
262
|
private
|
|
241
263
|
def draw_expanded_section(routes)
|
|
242
264
|
routes.map.each_with_index do |r, i|
|
|
@@ -267,7 +289,7 @@ module ActionDispatch
|
|
|
267
289
|
super
|
|
268
290
|
end
|
|
269
291
|
|
|
270
|
-
def no_routes(routes, filter)
|
|
292
|
+
def no_routes(engine, routes, filter)
|
|
271
293
|
@buffer <<
|
|
272
294
|
if filter.none?
|
|
273
295
|
"No unused routes found."
|
|
@@ -287,7 +309,7 @@ module ActionDispatch
|
|
|
287
309
|
end
|
|
288
310
|
|
|
289
311
|
def section_title(title)
|
|
290
|
-
@buffer << %(<tr><th colspan="
|
|
312
|
+
@buffer << %(<tr><th colspan="5">#{title}</th></tr>)
|
|
291
313
|
end
|
|
292
314
|
|
|
293
315
|
def section(routes)
|
|
@@ -298,6 +320,9 @@ module ActionDispatch
|
|
|
298
320
|
def header(routes)
|
|
299
321
|
end
|
|
300
322
|
|
|
323
|
+
def footer(routes)
|
|
324
|
+
end
|
|
325
|
+
|
|
301
326
|
def no_routes(*)
|
|
302
327
|
@buffer << <<~MESSAGE
|
|
303
328
|
<p>You don't have any routes defined!</p>
|