actionpack 6.1.7.5 → 7.1.3.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.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +355 -435
- data/MIT-LICENSE +2 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +33 -37
- data/lib/abstract_controller/caching/fragments.rb +4 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +50 -11
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +78 -30
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
- data/lib/abstract_controller/rendering.rb +12 -14
- data/lib/abstract_controller/translation.rb +26 -7
- data/lib/abstract_controller/url_for.rb +6 -6
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +12 -10
- data/lib/action_controller/base.rb +8 -21
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +4 -2
- data/lib/action_controller/log_subscriber.rb +20 -7
- data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +137 -102
- data/lib/action_controller/metal/content_security_policy.rb +37 -3
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +25 -31
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +27 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/head.rb +9 -7
- data/lib/action_controller/metal/helpers.rb +5 -16
- data/lib/action_controller/metal/http_authentication.rb +78 -42
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +62 -50
- data/lib/action_controller/metal/live.rb +67 -2
- data/lib/action_controller/metal/mime_responds.rb +5 -5
- data/lib/action_controller/metal/params_wrapper.rb +24 -13
- data/lib/action_controller/metal/permissions_policy.rb +20 -29
- data/lib/action_controller/metal/redirecting.rb +96 -23
- data/lib/action_controller/metal/renderers.rb +14 -15
- data/lib/action_controller/metal/rendering.rb +121 -16
- data/lib/action_controller/metal/request_forgery_protection.rb +208 -68
- data/lib/action_controller/metal/rescue.rb +7 -4
- data/lib/action_controller/metal/streaming.rb +74 -36
- data/lib/action_controller/metal/strong_parameters.rb +254 -151
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +10 -5
- data/lib/action_controller/metal.rb +89 -34
- data/lib/action_controller/railtie.rb +66 -9
- data/lib/action_controller/renderer.rb +99 -85
- data/lib/action_controller/test_case.rb +42 -11
- data/lib/action_controller.rb +10 -6
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +21 -16
- data/lib/action_dispatch/http/content_security_policy.rb +122 -44
- data/lib/action_dispatch/http/filter_parameters.rb +14 -23
- data/lib/action_dispatch/http/headers.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +25 -15
- data/lib/action_dispatch/http/mime_type.rb +43 -22
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +6 -6
- data/lib/action_dispatch/http/permissions_policy.rb +57 -19
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +75 -51
- data/lib/action_dispatch/http/response.rb +81 -77
- data/lib/action_dispatch/http/upload.rb +15 -2
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
- data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
- data/lib/action_dispatch/journey/nodes/node.rb +70 -5
- data/lib/action_dispatch/journey/path/pattern.rb +36 -27
- data/lib/action_dispatch/journey/route.rb +8 -14
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +10 -9
- data/lib/action_dispatch/journey/routes.rb +5 -5
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -7
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +97 -107
- data/lib/action_dispatch/middleware/debug_exceptions.rb +31 -28
- data/lib/action_dispatch/middleware/debug_locks.rb +7 -4
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +190 -27
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +24 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +19 -20
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +32 -19
- data/lib/action_dispatch/middleware/request_id.rb +5 -3
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +6 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -13
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +30 -25
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +34 -11
- data/lib/action_dispatch/middleware/static.rb +16 -16
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +5 -5
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +45 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- 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 +64 -55
- data/lib/action_dispatch/railtie.rb +20 -4
- data/lib/action_dispatch/request/session.rb +59 -19
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +55 -7
- data/lib/action_dispatch/routing/mapper.rb +117 -107
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +20 -8
- data/lib/action_dispatch/routing/route_set.rb +67 -27
- data/lib/action_dispatch/routing/routes_proxy.rb +11 -16
- data/lib/action_dispatch/routing/url_for.rb +29 -26
- data/lib/action_dispatch/routing.rb +12 -13
- data/lib/action_dispatch/system_test_case.rb +8 -8
- data/lib/action_dispatch/system_testing/browser.rb +20 -29
- data/lib/action_dispatch/system_testing/driver.rb +34 -18
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +35 -20
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +14 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +70 -30
- data/lib/action_dispatch/testing/assertions.rb +3 -4
- data/lib/action_dispatch/testing/integration.rb +33 -25
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +5 -30
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +34 -2
- data/lib/action_dispatch.rb +38 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +67 -30
@@ -4,7 +4,6 @@ require "active_support/core_ext/hash/slice"
|
|
4
4
|
require "active_support/core_ext/enumerable"
|
5
5
|
require "active_support/core_ext/array/extract_options"
|
6
6
|
require "active_support/core_ext/regexp"
|
7
|
-
require "active_support/core_ext/symbol/starts_ends_with"
|
8
7
|
require "action_dispatch/routing/redirection"
|
9
8
|
require "action_dispatch/routing/endpoint"
|
10
9
|
|
@@ -13,7 +12,10 @@ module ActionDispatch
|
|
13
12
|
class Mapper
|
14
13
|
URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
|
15
14
|
|
16
|
-
|
15
|
+
cattr_accessor :route_source_locations, instance_accessor: false, default: false
|
16
|
+
cattr_accessor :backtrace_cleaner, instance_accessor: false, default: ActiveSupport::BacktraceCleaner.new
|
17
|
+
|
18
|
+
class Constraints < Routing::Endpoint # :nodoc:
|
17
19
|
attr_reader :app, :constraints
|
18
20
|
|
19
21
|
SERVE = ->(app, req) { app.serve req }
|
@@ -44,7 +46,7 @@ module ActionDispatch
|
|
44
46
|
end
|
45
47
|
|
46
48
|
def serve(req)
|
47
|
-
return [ 404, {
|
49
|
+
return [ 404, { Constants::X_CASCADE => "pass" }, [] ] unless matches?(req)
|
48
50
|
|
49
51
|
@strategy.call @app, req
|
50
52
|
end
|
@@ -67,11 +69,11 @@ module ActionDispatch
|
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
70
|
-
class Mapping
|
72
|
+
class Mapping # :nodoc:
|
71
73
|
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
|
72
74
|
OPTIONAL_FORMAT_REGEX = %r{(?:\(\.:format\)+|\.:format|/)\Z}
|
73
75
|
|
74
|
-
attr_reader :requirements, :defaults, :to, :default_controller,
|
76
|
+
attr_reader :path, :requirements, :defaults, :to, :default_controller,
|
75
77
|
:default_action, :required_defaults, :ast, :scope_options
|
76
78
|
|
77
79
|
def self.build(scope, set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
@@ -122,31 +124,17 @@ module ActionDispatch
|
|
122
124
|
@to = intern(to)
|
123
125
|
@default_controller = intern(controller)
|
124
126
|
@default_action = intern(default_action)
|
125
|
-
@ast = ast
|
126
127
|
@anchor = anchor
|
127
128
|
@via = via
|
128
129
|
@internal = options.delete(:internal)
|
129
130
|
@scope_options = scope_params[:options]
|
131
|
+
ast = Journey::Ast.new(ast, formatted)
|
130
132
|
|
131
|
-
|
132
|
-
wildcard_options = {}
|
133
|
-
ast.each do |node|
|
134
|
-
if node.symbol?
|
135
|
-
path_params << node.to_sym
|
136
|
-
elsif formatted != false && node.star?
|
137
|
-
# Add a constraint for wildcard route to make it non-greedy and match the
|
138
|
-
# optional format part of the route by default.
|
139
|
-
wildcard_options[node.name.to_sym] ||= /.+?/
|
140
|
-
elsif node.cat?
|
141
|
-
alter_regex_for_custom_routes(node)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
options = wildcard_options.merge!(options)
|
133
|
+
options = ast.wildcard_options.merge!(options)
|
146
134
|
|
147
|
-
options = normalize_options!(options, path_params, scope_params[:module])
|
135
|
+
options = normalize_options!(options, ast.path_params, scope_params[:module])
|
148
136
|
|
149
|
-
split_options = constraints(options, path_params)
|
137
|
+
split_options = constraints(options, ast.path_params)
|
150
138
|
|
151
139
|
constraints = scope_params[:constraints].merge Hash[split_options[:constraints] || []]
|
152
140
|
|
@@ -160,8 +148,8 @@ module ActionDispatch
|
|
160
148
|
@blocks = blocks(options_constraints)
|
161
149
|
end
|
162
150
|
|
163
|
-
requirements, conditions = split_constraints path_params, constraints
|
164
|
-
verify_regexp_requirements requirements.
|
151
|
+
requirements, conditions = split_constraints ast.path_params, constraints
|
152
|
+
verify_regexp_requirements requirements, ast.wildcard_options
|
165
153
|
|
166
154
|
formats = normalize_format(formatted)
|
167
155
|
|
@@ -169,30 +157,29 @@ module ActionDispatch
|
|
169
157
|
@conditions = Hash[conditions]
|
170
158
|
@defaults = formats[:defaults].merge(@defaults).merge(normalize_defaults(options))
|
171
159
|
|
172
|
-
if path_params.include?(:action) && !@requirements.key?(:action)
|
160
|
+
if ast.path_params.include?(:action) && !@requirements.key?(:action)
|
173
161
|
@defaults[:action] ||= "index"
|
174
162
|
end
|
175
163
|
|
176
164
|
@required_defaults = (split_options[:required_defaults] || []).map(&:first)
|
165
|
+
|
166
|
+
ast.requirements = @requirements
|
167
|
+
@path = Journey::Path::Pattern.new(ast, @requirements, JOINED_SEPARATORS, @anchor)
|
177
168
|
end
|
178
169
|
|
170
|
+
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
171
|
+
|
179
172
|
def make_route(name, precedence)
|
180
173
|
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
|
181
174
|
required_defaults: required_defaults, defaults: defaults,
|
182
175
|
request_method_match: request_method, precedence: precedence,
|
183
|
-
scope_options: scope_options, internal: @internal)
|
176
|
+
scope_options: scope_options, internal: @internal, source_location: route_source_location)
|
184
177
|
end
|
185
178
|
|
186
179
|
def application
|
187
180
|
app(@blocks)
|
188
181
|
end
|
189
182
|
|
190
|
-
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
191
|
-
|
192
|
-
def path
|
193
|
-
Journey::Path::Pattern.new(@ast, requirements, JOINED_SEPARATORS, @anchor)
|
194
|
-
end
|
195
|
-
|
196
183
|
def conditions
|
197
184
|
build_conditions @conditions, @set.request_class
|
198
185
|
end
|
@@ -212,24 +199,6 @@ module ActionDispatch
|
|
212
199
|
private :request_method
|
213
200
|
|
214
201
|
private
|
215
|
-
# Find all the symbol nodes that are adjacent to literal nodes and alter
|
216
|
-
# the regexp so that Journey will partition them into custom routes.
|
217
|
-
def alter_regex_for_custom_routes(node)
|
218
|
-
if node.left.literal? && node.right.symbol?
|
219
|
-
symbol = node.right
|
220
|
-
elsif node.left.literal? && node.right.cat? && node.right.left.symbol?
|
221
|
-
symbol = node.right.left
|
222
|
-
elsif node.left.symbol? && node.right.literal?
|
223
|
-
symbol = node.left
|
224
|
-
elsif node.left.symbol? && node.right.cat? && node.right.left.literal?
|
225
|
-
symbol = node.left
|
226
|
-
end
|
227
|
-
|
228
|
-
if symbol
|
229
|
-
symbol.regexp = /(?:#{Regexp.union(symbol.regexp, '-')})+/
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
202
|
def intern(object)
|
234
203
|
object.is_a?(String) ? -object : object
|
235
204
|
end
|
@@ -248,9 +217,16 @@ module ActionDispatch
|
|
248
217
|
if to.respond_to?(:action) || to.respond_to?(:call)
|
249
218
|
options
|
250
219
|
else
|
251
|
-
|
252
|
-
|
253
|
-
|
220
|
+
if to.nil?
|
221
|
+
controller = default_controller
|
222
|
+
action = default_action
|
223
|
+
elsif to.is_a?(String) && to.include?("#")
|
224
|
+
to_endpoint = to.split("#").map!(&:-@)
|
225
|
+
controller = to_endpoint[0]
|
226
|
+
action = to_endpoint[1]
|
227
|
+
else
|
228
|
+
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#'"
|
229
|
+
end
|
254
230
|
|
255
231
|
controller = add_controller_module(controller, modyoule)
|
256
232
|
|
@@ -280,14 +256,18 @@ module ActionDispatch
|
|
280
256
|
end
|
281
257
|
end
|
282
258
|
|
283
|
-
def verify_regexp_requirements(requirements)
|
284
|
-
requirements.each do |requirement|
|
285
|
-
|
259
|
+
def verify_regexp_requirements(requirements, wildcard_options)
|
260
|
+
requirements.each do |requirement, regex|
|
261
|
+
next unless regex.is_a? Regexp
|
262
|
+
|
263
|
+
if ANCHOR_CHARACTERS_REGEX.match?(regex.source)
|
286
264
|
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
|
287
265
|
end
|
288
266
|
|
289
|
-
if
|
290
|
-
|
267
|
+
if regex.multiline?
|
268
|
+
next if wildcard_options.key?(requirement)
|
269
|
+
|
270
|
+
raise ArgumentError, "Regexp multiline option is not allowed in routing requirements: #{regex.inspect}"
|
291
271
|
end
|
292
272
|
end
|
293
273
|
end
|
@@ -335,14 +315,6 @@ module ActionDispatch
|
|
335
315
|
hash
|
336
316
|
end
|
337
317
|
|
338
|
-
def split_to(to)
|
339
|
-
if /#/.match?(to)
|
340
|
-
to.split("#").map!(&:-@)
|
341
|
-
else
|
342
|
-
[]
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
318
|
def add_controller_module(controller, modyoule)
|
347
319
|
if modyoule && !controller.is_a?(Regexp)
|
348
320
|
if controller&.start_with?("/")
|
@@ -386,6 +358,15 @@ module ActionDispatch
|
|
386
358
|
def dispatcher(raise_on_name_error)
|
387
359
|
Routing::RouteSet::Dispatcher.new raise_on_name_error
|
388
360
|
end
|
361
|
+
|
362
|
+
def route_source_location
|
363
|
+
if Mapper.route_source_locations
|
364
|
+
action_dispatch_dir = File.expand_path("..", __dir__)
|
365
|
+
caller_location = caller_locations.find { |location| !location.path.include?(action_dispatch_dir) }
|
366
|
+
cleaned_path = Mapper.backtrace_cleaner.clean([caller_location.path]).first
|
367
|
+
"#{cleaned_path}:#{caller_location.lineno}" if cleaned_path
|
368
|
+
end
|
369
|
+
end
|
389
370
|
end
|
390
371
|
|
391
372
|
# Invokes Journey::Router::Utils.normalize_path, then ensures that
|
@@ -420,10 +401,10 @@ module ActionDispatch
|
|
420
401
|
#
|
421
402
|
# If you want to expose your action to both GET and POST, use:
|
422
403
|
#
|
423
|
-
# # sets :controller, :action and :id in params
|
404
|
+
# # sets :controller, :action, and :id in params
|
424
405
|
# match ':controller/:action/:id', via: [:get, :post]
|
425
406
|
#
|
426
|
-
# Note that +:controller+, +:action
|
407
|
+
# Note that +:controller+, +:action+, and +:id+ are interpreted as URL
|
427
408
|
# query parameters and thus available through +params+ in an action.
|
428
409
|
#
|
429
410
|
# If you want to expose your action to GET, use +get+ in the router:
|
@@ -639,7 +620,7 @@ module ActionDispatch
|
|
639
620
|
target_as = name_for_action(options[:as], path)
|
640
621
|
options[:via] ||= :all
|
641
622
|
|
642
|
-
match(path,
|
623
|
+
match(path, { to: app, anchor: false, format: false }.merge(options))
|
643
624
|
|
644
625
|
define_generate_prefix(app, target_as) if rails_app
|
645
626
|
self
|
@@ -682,7 +663,7 @@ module ActionDispatch
|
|
682
663
|
|
683
664
|
script_namer = ->(options) do
|
684
665
|
prefix_options = options.slice(*_route.segment_keys)
|
685
|
-
prefix_options[:
|
666
|
+
prefix_options[:script_name] = "" if options[:original_script_name]
|
686
667
|
|
687
668
|
if options[:_recall]
|
688
669
|
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
|
@@ -778,7 +759,7 @@ module ActionDispatch
|
|
778
759
|
# end
|
779
760
|
#
|
780
761
|
# This will create a number of routes for each of the posts and comments
|
781
|
-
# controller. For
|
762
|
+
# controller. For +Admin::PostsController+, \Rails will create:
|
782
763
|
#
|
783
764
|
# GET /admin/posts
|
784
765
|
# GET /admin/posts/new
|
@@ -789,7 +770,7 @@ module ActionDispatch
|
|
789
770
|
# DELETE /admin/posts/1
|
790
771
|
#
|
791
772
|
# If you want to route /posts (without the prefix /admin) to
|
792
|
-
#
|
773
|
+
# +Admin::PostsController+, you could use
|
793
774
|
#
|
794
775
|
# scope module: "admin" do
|
795
776
|
# resources :posts
|
@@ -838,7 +819,7 @@ module ActionDispatch
|
|
838
819
|
#
|
839
820
|
# Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
|
840
821
|
#
|
841
|
-
# # route /posts (without the prefix /admin) to
|
822
|
+
# # route /posts (without the prefix /admin) to +Admin::PostsController+
|
842
823
|
# scope module: "admin" do
|
843
824
|
# resources :posts
|
844
825
|
# end
|
@@ -936,7 +917,7 @@ module ActionDispatch
|
|
936
917
|
#
|
937
918
|
# === Options
|
938
919
|
#
|
939
|
-
# The +:path+, +:as+, +:module+, +:shallow_path
|
920
|
+
# The +:path+, +:as+, +:module+, +:shallow_path+, and +:shallow_prefix+
|
940
921
|
# options all default to the name of the namespace.
|
941
922
|
#
|
942
923
|
# For options, see <tt>Base#match</tt>. For +:shallow_path+ option, see
|
@@ -947,7 +928,7 @@ module ActionDispatch
|
|
947
928
|
# resources :posts
|
948
929
|
# end
|
949
930
|
#
|
950
|
-
# # maps to
|
931
|
+
# # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
|
951
932
|
# namespace :admin, module: "sekret" do
|
952
933
|
# resources :posts
|
953
934
|
# end
|
@@ -956,7 +937,7 @@ module ActionDispatch
|
|
956
937
|
# namespace :admin, as: "sekret" do
|
957
938
|
# resources :posts
|
958
939
|
# end
|
959
|
-
def namespace(path, options = {})
|
940
|
+
def namespace(path, options = {}, &block)
|
960
941
|
path = path.to_s
|
961
942
|
|
962
943
|
defaults = {
|
@@ -967,7 +948,7 @@ module ActionDispatch
|
|
967
948
|
}
|
968
949
|
|
969
950
|
path_scope(options.delete(:path) { path }) do
|
970
|
-
scope(defaults.merge!(options))
|
951
|
+
scope(defaults.merge!(options), &block)
|
971
952
|
end
|
972
953
|
end
|
973
954
|
|
@@ -1026,8 +1007,8 @@ module ActionDispatch
|
|
1026
1007
|
# constraints(Iphone) do
|
1027
1008
|
# resources :iphones
|
1028
1009
|
# end
|
1029
|
-
def constraints(constraints = {})
|
1030
|
-
scope(constraints: constraints)
|
1010
|
+
def constraints(constraints = {}, &block)
|
1011
|
+
scope(constraints: constraints, &block)
|
1031
1012
|
end
|
1032
1013
|
|
1033
1014
|
# Allows you to set default parameters for a route, such as this:
|
@@ -1112,7 +1093,7 @@ module ActionDispatch
|
|
1112
1093
|
|
1113
1094
|
# Resource routing allows you to quickly declare all of the common routes
|
1114
1095
|
# for a given resourceful controller. Instead of declaring separate routes
|
1115
|
-
# for your +index+, +show+, +new+, +edit+, +create+, +update
|
1096
|
+
# for your +index+, +show+, +new+, +edit+, +create+, +update+, and +destroy+
|
1116
1097
|
# actions, a resourceful route declares them in a single line of code:
|
1117
1098
|
#
|
1118
1099
|
# resources :photos
|
@@ -1156,7 +1137,7 @@ module ActionDispatch
|
|
1156
1137
|
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
1157
1138
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
1158
1139
|
|
1159
|
-
class Resource
|
1140
|
+
class Resource # :nodoc:
|
1160
1141
|
attr_reader :controller, :path, :param
|
1161
1142
|
|
1162
1143
|
def initialize(entities, api_only, shallow, options = {})
|
@@ -1251,7 +1232,7 @@ module ActionDispatch
|
|
1251
1232
|
def singleton?; false; end
|
1252
1233
|
end
|
1253
1234
|
|
1254
|
-
class SingletonResource < Resource
|
1235
|
+
class SingletonResource < Resource # :nodoc:
|
1255
1236
|
def initialize(entities, api_only, shallow, options)
|
1256
1237
|
super
|
1257
1238
|
@as = nil
|
@@ -1307,6 +1288,16 @@ module ActionDispatch
|
|
1307
1288
|
# DELETE /profile
|
1308
1289
|
# POST /profile
|
1309
1290
|
#
|
1291
|
+
# If you want instances of a model to work with this resource via
|
1292
|
+
# record identification (e.g. in +form_with+ or +redirect_to+), you
|
1293
|
+
# will need to call resolve[rdoc-ref:CustomUrls#resolve]:
|
1294
|
+
#
|
1295
|
+
# resource :profile
|
1296
|
+
# resolve('Profile') { [:profile] }
|
1297
|
+
#
|
1298
|
+
# # Enables this to work with singular routes:
|
1299
|
+
# form_with(model: @profile) {}
|
1300
|
+
#
|
1310
1301
|
# === Options
|
1311
1302
|
# Takes same options as resources[rdoc-ref:#resources]
|
1312
1303
|
def resource(*resources, &block)
|
@@ -1338,7 +1329,7 @@ module ActionDispatch
|
|
1338
1329
|
self
|
1339
1330
|
end
|
1340
1331
|
|
1341
|
-
# In Rails, a resourceful route provides a mapping between HTTP verbs
|
1332
|
+
# In \Rails, a resourceful route provides a mapping between HTTP verbs
|
1342
1333
|
# and URLs and controller actions. By convention, each action also maps
|
1343
1334
|
# to particular CRUD operations in a database. A single entry in the
|
1344
1335
|
# routing file, such as
|
@@ -1470,7 +1461,7 @@ module ActionDispatch
|
|
1470
1461
|
#
|
1471
1462
|
# === Examples
|
1472
1463
|
#
|
1473
|
-
# # routes call
|
1464
|
+
# # routes call +Admin::PostsController+
|
1474
1465
|
# resources :posts, module: "admin"
|
1475
1466
|
#
|
1476
1467
|
# # resource actions are at /admin/posts.
|
@@ -1513,19 +1504,17 @@ module ActionDispatch
|
|
1513
1504
|
# end
|
1514
1505
|
# end
|
1515
1506
|
#
|
1516
|
-
# This will enable Rails to recognize paths such as <tt>/photos/search</tt>
|
1507
|
+
# This will enable \Rails to recognize paths such as <tt>/photos/search</tt>
|
1517
1508
|
# with GET, and route to the search action of +PhotosController+. It will also
|
1518
1509
|
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
|
1519
1510
|
# route helpers.
|
1520
|
-
def collection
|
1511
|
+
def collection(&block)
|
1521
1512
|
unless resource_scope?
|
1522
1513
|
raise ArgumentError, "can't use collection outside resource(s) scope"
|
1523
1514
|
end
|
1524
1515
|
|
1525
1516
|
with_scope_level(:collection) do
|
1526
|
-
path_scope(parent_resource.collection_scope)
|
1527
|
-
yield
|
1528
|
-
end
|
1517
|
+
path_scope(parent_resource.collection_scope, &block)
|
1529
1518
|
end
|
1530
1519
|
end
|
1531
1520
|
|
@@ -1540,7 +1529,7 @@ module ActionDispatch
|
|
1540
1529
|
# This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
|
1541
1530
|
# preview action of +PhotosController+. It will also create the
|
1542
1531
|
# <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
|
1543
|
-
def member
|
1532
|
+
def member(&block)
|
1544
1533
|
unless resource_scope?
|
1545
1534
|
raise ArgumentError, "can't use member outside resource(s) scope"
|
1546
1535
|
end
|
@@ -1548,27 +1537,25 @@ module ActionDispatch
|
|
1548
1537
|
with_scope_level(:member) do
|
1549
1538
|
if shallow?
|
1550
1539
|
shallow_scope {
|
1551
|
-
path_scope(parent_resource.member_scope)
|
1540
|
+
path_scope(parent_resource.member_scope, &block)
|
1552
1541
|
}
|
1553
1542
|
else
|
1554
|
-
path_scope(parent_resource.member_scope)
|
1543
|
+
path_scope(parent_resource.member_scope, &block)
|
1555
1544
|
end
|
1556
1545
|
end
|
1557
1546
|
end
|
1558
1547
|
|
1559
|
-
def new
|
1548
|
+
def new(&block)
|
1560
1549
|
unless resource_scope?
|
1561
1550
|
raise ArgumentError, "can't use new outside resource(s) scope"
|
1562
1551
|
end
|
1563
1552
|
|
1564
1553
|
with_scope_level(:new) do
|
1565
|
-
path_scope(parent_resource.new_scope(action_path(:new)))
|
1566
|
-
yield
|
1567
|
-
end
|
1554
|
+
path_scope(parent_resource.new_scope(action_path(:new)), &block)
|
1568
1555
|
end
|
1569
1556
|
end
|
1570
1557
|
|
1571
|
-
def nested
|
1558
|
+
def nested(&block)
|
1572
1559
|
unless resource_scope?
|
1573
1560
|
raise ArgumentError, "can't use nested outside resource(s) scope"
|
1574
1561
|
end
|
@@ -1577,12 +1564,12 @@ module ActionDispatch
|
|
1577
1564
|
if shallow? && shallow_nesting_depth >= 1
|
1578
1565
|
shallow_scope do
|
1579
1566
|
path_scope(parent_resource.nested_scope) do
|
1580
|
-
scope(nested_options)
|
1567
|
+
scope(nested_options, &block)
|
1581
1568
|
end
|
1582
1569
|
end
|
1583
1570
|
else
|
1584
1571
|
path_scope(parent_resource.nested_scope) do
|
1585
|
-
scope(nested_options)
|
1572
|
+
scope(nested_options, &block)
|
1586
1573
|
end
|
1587
1574
|
end
|
1588
1575
|
end
|
@@ -1608,6 +1595,29 @@ module ActionDispatch
|
|
1608
1595
|
!parent_resource.singleton? && @scope[:shallow]
|
1609
1596
|
end
|
1610
1597
|
|
1598
|
+
# Loads another routes file with the given +name+ located inside the
|
1599
|
+
# +config/routes+ directory. In that file, you can use the normal
|
1600
|
+
# routing DSL, but <i>do not</i> surround it with a
|
1601
|
+
# +Rails.application.routes.draw+ block.
|
1602
|
+
#
|
1603
|
+
# # config/routes.rb
|
1604
|
+
# Rails.application.routes.draw do
|
1605
|
+
# draw :admin # Loads `config/routes/admin.rb`
|
1606
|
+
# draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb`
|
1607
|
+
# end
|
1608
|
+
#
|
1609
|
+
# # config/routes/admin.rb
|
1610
|
+
# namespace :admin do
|
1611
|
+
# resources :accounts
|
1612
|
+
# end
|
1613
|
+
#
|
1614
|
+
# # config/routes/third_party/some_gem.rb
|
1615
|
+
# mount SomeGem::Engine, at: "/some_gem"
|
1616
|
+
#
|
1617
|
+
# <b>CAUTION:</b> Use this feature with care. Having multiple routes
|
1618
|
+
# files can negatively impact discoverability and readability. For most
|
1619
|
+
# applications — even those with a few hundred routes — it's easier for
|
1620
|
+
# developers to have a single routes file.
|
1611
1621
|
def draw(name)
|
1612
1622
|
path = @draw_paths.find do |_path|
|
1613
1623
|
File.exist? "#{_path}/#{name}.rb"
|
@@ -1641,7 +1651,7 @@ module ActionDispatch
|
|
1641
1651
|
when Symbol
|
1642
1652
|
options[:action] = to
|
1643
1653
|
when String
|
1644
|
-
if
|
1654
|
+
if to.include?("#")
|
1645
1655
|
options[:to] = to
|
1646
1656
|
else
|
1647
1657
|
options[:controller] = to
|
@@ -1664,7 +1674,7 @@ module ActionDispatch
|
|
1664
1674
|
end
|
1665
1675
|
end
|
1666
1676
|
|
1667
|
-
# You can specify what Rails should route "/" to with the root method:
|
1677
|
+
# You can specify what \Rails should route "/" to with the root method:
|
1668
1678
|
#
|
1669
1679
|
# root to: 'pages#main'
|
1670
1680
|
#
|
@@ -1676,7 +1686,7 @@ module ActionDispatch
|
|
1676
1686
|
#
|
1677
1687
|
# You should put the root route at the top of <tt>config/routes.rb</tt>,
|
1678
1688
|
# because this means it will be matched first. As this is the most popular route
|
1679
|
-
# of most Rails applications, this is beneficial.
|
1689
|
+
# of most \Rails applications, this is beneficial.
|
1680
1690
|
def root(path, options = {})
|
1681
1691
|
if path.is_a?(String)
|
1682
1692
|
options[:to] = path
|
@@ -1768,10 +1778,10 @@ module ActionDispatch
|
|
1768
1778
|
@scope = @scope.parent
|
1769
1779
|
end
|
1770
1780
|
|
1771
|
-
def resource_scope(resource)
|
1781
|
+
def resource_scope(resource, &block)
|
1772
1782
|
@scope = @scope.new(scope_level_resource: resource)
|
1773
1783
|
|
1774
|
-
controller(resource.resource_scope)
|
1784
|
+
controller(resource.resource_scope, &block)
|
1775
1785
|
ensure
|
1776
1786
|
@scope = @scope.parent
|
1777
1787
|
end
|
@@ -1889,7 +1899,7 @@ module ActionDispatch
|
|
1889
1899
|
end
|
1890
1900
|
|
1891
1901
|
def map_match(paths, options)
|
1892
|
-
if options[:on] && !VALID_ON_OPTIONS.include?(
|
1902
|
+
if (on = options[:on]) && !VALID_ON_OPTIONS.include?(on)
|
1893
1903
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
1894
1904
|
end
|
1895
1905
|
|
@@ -2300,7 +2310,7 @@ module ActionDispatch
|
|
2300
2310
|
NULL = Scope.new(nil, nil)
|
2301
2311
|
end
|
2302
2312
|
|
2303
|
-
def initialize(set)
|
2313
|
+
def initialize(set) # :nodoc:
|
2304
2314
|
@set = set
|
2305
2315
|
@draw_paths = set.draw_paths
|
2306
2316
|
@scope = Scope.new(path_names: @set.resources_path_names)
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module ActionDispatch
|
4
4
|
module Routing
|
5
|
+
# = Action Dispatch Routing \PolymorphicRoutes
|
6
|
+
#
|
5
7
|
# Polymorphic URL helpers are methods for smart resolution to a named route call when
|
6
8
|
# given an Active Record model instance. They are to be used in combination with
|
7
9
|
# ActionController::Resources.
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "action_dispatch/http/request"
|
4
|
-
require "active_support/core_ext/uri"
|
5
3
|
require "active_support/core_ext/array/extract_options"
|
6
4
|
require "rack/utils"
|
7
5
|
require "action_controller/metal/exceptions"
|
@@ -20,10 +18,19 @@ module ActionDispatch
|
|
20
18
|
def redirect?; true; end
|
21
19
|
|
22
20
|
def call(env)
|
23
|
-
|
21
|
+
ActiveSupport::Notifications.instrument("redirect.action_dispatch") do |payload|
|
22
|
+
request = Request.new(env)
|
23
|
+
response = build_response(request)
|
24
|
+
|
25
|
+
payload[:status] = @status
|
26
|
+
payload[:location] = response.headers["Location"]
|
27
|
+
payload[:request] = request
|
28
|
+
|
29
|
+
response.to_a
|
30
|
+
end
|
24
31
|
end
|
25
32
|
|
26
|
-
def
|
33
|
+
def build_response(req)
|
27
34
|
uri = URI.parse(path(req.path_parameters, req))
|
28
35
|
|
29
36
|
unless uri.host
|
@@ -40,15 +47,15 @@ module ActionDispatch
|
|
40
47
|
|
41
48
|
req.commit_flash
|
42
49
|
|
43
|
-
body =
|
50
|
+
body = ""
|
44
51
|
|
45
52
|
headers = {
|
46
53
|
"Location" => uri.to_s,
|
47
|
-
"Content-Type" => "text/html",
|
54
|
+
"Content-Type" => "text/html; charset=#{ActionDispatch::Response.default_charset}",
|
48
55
|
"Content-Length" => body.length.to_s
|
49
56
|
}
|
50
57
|
|
51
|
-
|
58
|
+
ActionDispatch::Response.new(status, headers, body)
|
52
59
|
end
|
53
60
|
|
54
61
|
def path(params, request)
|
@@ -61,7 +68,7 @@ module ActionDispatch
|
|
61
68
|
|
62
69
|
private
|
63
70
|
def relative_path?(path)
|
64
|
-
path && !path.empty? && path
|
71
|
+
path && !path.empty? && !path.start_with?("/")
|
65
72
|
end
|
66
73
|
|
67
74
|
def escape(params)
|
@@ -144,6 +151,11 @@ module ActionDispatch
|
|
144
151
|
# This will redirect the user, while ignoring certain parts of the request, including query string, etc.
|
145
152
|
# <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, etc all redirect to <tt>/posts</tt>.
|
146
153
|
#
|
154
|
+
# The redirect will use a <tt>301 Moved Permanently</tt> status code by
|
155
|
+
# default. This can be overridden with the +:status+ option:
|
156
|
+
#
|
157
|
+
# get "/stories" => redirect("/posts", status: 307)
|
158
|
+
#
|
147
159
|
# You can also use interpolation in the supplied redirect argument:
|
148
160
|
#
|
149
161
|
# get 'docs/:article', to: redirect('/wiki/%{article}')
|