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,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/hash/slice"
|
|
4
6
|
require "active_support/core_ext/enumerable"
|
|
5
7
|
require "active_support/core_ext/array/extract_options"
|
|
@@ -10,8 +12,20 @@ require "action_dispatch/routing/endpoint"
|
|
|
10
12
|
module ActionDispatch
|
|
11
13
|
module Routing
|
|
12
14
|
class Mapper
|
|
15
|
+
class BacktraceCleaner < ActiveSupport::BacktraceCleaner # :nodoc:
|
|
16
|
+
def initialize
|
|
17
|
+
super
|
|
18
|
+
remove_silencers!
|
|
19
|
+
add_core_silencer
|
|
20
|
+
add_stdlib_silencer
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
13
24
|
URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
|
|
14
25
|
|
|
26
|
+
cattr_accessor :route_source_locations, instance_accessor: false, default: false
|
|
27
|
+
cattr_accessor :backtrace_cleaner, instance_accessor: false, default: BacktraceCleaner.new
|
|
28
|
+
|
|
15
29
|
class Constraints < Routing::Endpoint # :nodoc:
|
|
16
30
|
attr_reader :app, :constraints
|
|
17
31
|
|
|
@@ -19,10 +33,10 @@ module ActionDispatch
|
|
|
19
33
|
CALL = ->(app, req) { app.call req.env }
|
|
20
34
|
|
|
21
35
|
def initialize(app, constraints, strategy)
|
|
22
|
-
# Unwrap Constraints objects. I don't actually think it's possible
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
36
|
+
# Unwrap Constraints objects. I don't actually think it's possible to pass a
|
|
37
|
+
# Constraints object to this constructor, but there were multiple places that
|
|
38
|
+
# kept testing children of this object. I **think** they were just being
|
|
39
|
+
# defensive, but I have no idea.
|
|
26
40
|
if app.is_a?(self.class)
|
|
27
41
|
constraints += app.constraints
|
|
28
42
|
app = app.app
|
|
@@ -43,7 +57,7 @@ module ActionDispatch
|
|
|
43
57
|
end
|
|
44
58
|
|
|
45
59
|
def serve(req)
|
|
46
|
-
return [ 404, {
|
|
60
|
+
return [ 404, { Constants::X_CASCADE => "pass" }, [] ] unless matches?(req)
|
|
47
61
|
|
|
48
62
|
@strategy.call @app, req
|
|
49
63
|
end
|
|
@@ -170,7 +184,7 @@ module ActionDispatch
|
|
|
170
184
|
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
|
|
171
185
|
required_defaults: required_defaults, defaults: defaults,
|
|
172
186
|
request_method_match: request_method, precedence: precedence,
|
|
173
|
-
scope_options: scope_options, internal: @internal)
|
|
187
|
+
scope_options: scope_options, internal: @internal, source_location: route_source_location)
|
|
174
188
|
end
|
|
175
189
|
|
|
176
190
|
def application
|
|
@@ -207,16 +221,28 @@ module ActionDispatch
|
|
|
207
221
|
# Add a default constraint for :controller path segments that matches namespaced
|
|
208
222
|
# controllers with default routes like :controller/:action/:id(.:format), e.g:
|
|
209
223
|
# GET /admin/products/show/1
|
|
210
|
-
#
|
|
224
|
+
# # > { controller: 'admin/products', action: 'show', id: '1' }
|
|
211
225
|
options[:controller] ||= /.+?/
|
|
212
226
|
end
|
|
213
227
|
|
|
214
228
|
if to.respond_to?(:action) || to.respond_to?(:call)
|
|
215
229
|
options
|
|
216
230
|
else
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
231
|
+
if to.nil?
|
|
232
|
+
controller = default_controller
|
|
233
|
+
action = default_action
|
|
234
|
+
elsif to.is_a?(String)
|
|
235
|
+
if to.include?("#")
|
|
236
|
+
to_endpoint = to.split("#").map!(&:-@)
|
|
237
|
+
controller = to_endpoint[0]
|
|
238
|
+
action = to_endpoint[1]
|
|
239
|
+
else
|
|
240
|
+
controller = default_controller
|
|
241
|
+
action = to
|
|
242
|
+
end
|
|
243
|
+
else
|
|
244
|
+
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#', or the controller should be implicit"
|
|
245
|
+
end
|
|
220
246
|
|
|
221
247
|
controller = add_controller_module(controller, modyoule)
|
|
222
248
|
|
|
@@ -305,14 +331,6 @@ module ActionDispatch
|
|
|
305
331
|
hash
|
|
306
332
|
end
|
|
307
333
|
|
|
308
|
-
def split_to(to)
|
|
309
|
-
if /#/.match?(to)
|
|
310
|
-
to.split("#").map!(&:-@)
|
|
311
|
-
else
|
|
312
|
-
[]
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
|
|
316
334
|
def add_controller_module(controller, modyoule)
|
|
317
335
|
if modyoule && !controller.is_a?(Regexp)
|
|
318
336
|
if controller&.start_with?("/")
|
|
@@ -356,24 +374,54 @@ module ActionDispatch
|
|
|
356
374
|
def dispatcher(raise_on_name_error)
|
|
357
375
|
Routing::RouteSet::Dispatcher.new raise_on_name_error
|
|
358
376
|
end
|
|
377
|
+
|
|
378
|
+
if Thread.respond_to?(:each_caller_location)
|
|
379
|
+
def route_source_location
|
|
380
|
+
if Mapper.route_source_locations
|
|
381
|
+
action_dispatch_dir = File.expand_path("..", __dir__)
|
|
382
|
+
Thread.each_caller_location do |location|
|
|
383
|
+
next if location.path.start_with?(action_dispatch_dir)
|
|
384
|
+
|
|
385
|
+
cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
|
|
386
|
+
next if cleaned_path.nil?
|
|
387
|
+
|
|
388
|
+
return "#{cleaned_path}:#{location.lineno}"
|
|
389
|
+
end
|
|
390
|
+
nil
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
else
|
|
394
|
+
def route_source_location
|
|
395
|
+
if Mapper.route_source_locations
|
|
396
|
+
action_dispatch_dir = File.expand_path("..", __dir__)
|
|
397
|
+
caller_locations.each do |location|
|
|
398
|
+
next if location.path.start_with?(action_dispatch_dir)
|
|
399
|
+
|
|
400
|
+
cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
|
|
401
|
+
next if cleaned_path.nil?
|
|
402
|
+
|
|
403
|
+
return "#{cleaned_path}:#{location.lineno}"
|
|
404
|
+
end
|
|
405
|
+
nil
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
end
|
|
359
409
|
end
|
|
360
410
|
|
|
361
|
-
# Invokes Journey::Router::Utils.normalize_path, then ensures that
|
|
362
|
-
#
|
|
363
|
-
#
|
|
411
|
+
# Invokes Journey::Router::Utils.normalize_path, then ensures that /(:locale)
|
|
412
|
+
# becomes (/:locale). Except for root cases, where the former is the correct
|
|
413
|
+
# one.
|
|
364
414
|
def self.normalize_path(path)
|
|
365
415
|
path = Journey::Router::Utils.normalize_path(path)
|
|
366
416
|
|
|
367
417
|
# the path for a root URL at this point can be something like
|
|
368
418
|
# "/(/:locale)(/:platform)/(:browser)", and we would want
|
|
369
|
-
# "/(:locale)(/:platform)(/:browser)"
|
|
370
|
-
|
|
371
|
-
# reverse "/(", "/((" etc to "(/", "((/" etc
|
|
419
|
+
# "/(:locale)(/:platform)(/:browser)" reverse "/(", "/((" etc to "(/", "((/" etc
|
|
372
420
|
path.gsub!(%r{/(\(+)/?}, '\1/')
|
|
373
|
-
# if a path is all optional segments, change the leading "(/" back to
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
#
|
|
421
|
+
# if a path is all optional segments, change the leading "(/" back to "/(" so it
|
|
422
|
+
# evaluates to "/" when interpreted with no options. Unless, however, at least
|
|
423
|
+
# one secondary segment consists of a static part, ex.
|
|
424
|
+
# "(/:locale)(/pages/:page)"
|
|
377
425
|
path.sub!(%r{^(\(+)/}, '/\1') if %r{^(\(+[^)]+\))(\(+/:[^)]+\))*$}.match?(path)
|
|
378
426
|
path
|
|
379
427
|
end
|
|
@@ -385,206 +433,202 @@ module ActionDispatch
|
|
|
385
433
|
module Base
|
|
386
434
|
# Matches a URL pattern to one or more routes.
|
|
387
435
|
#
|
|
388
|
-
# You should not use the
|
|
389
|
-
#
|
|
436
|
+
# You should not use the `match` method in your router without specifying an
|
|
437
|
+
# HTTP method.
|
|
390
438
|
#
|
|
391
439
|
# If you want to expose your action to both GET and POST, use:
|
|
392
440
|
#
|
|
393
|
-
#
|
|
394
|
-
#
|
|
441
|
+
# # sets :controller, :action, and :id in params
|
|
442
|
+
# match ':controller/:action/:id', via: [:get, :post]
|
|
395
443
|
#
|
|
396
|
-
# Note that
|
|
397
|
-
#
|
|
444
|
+
# Note that `:controller`, `:action`, and `:id` are interpreted as URL query
|
|
445
|
+
# parameters and thus available through `params` in an action.
|
|
398
446
|
#
|
|
399
|
-
# If you want to expose your action to GET, use
|
|
447
|
+
# If you want to expose your action to GET, use `get` in the router:
|
|
400
448
|
#
|
|
401
449
|
# Instead of:
|
|
402
450
|
#
|
|
403
|
-
#
|
|
451
|
+
# match ":controller/:action/:id"
|
|
404
452
|
#
|
|
405
453
|
# Do:
|
|
406
454
|
#
|
|
407
|
-
#
|
|
455
|
+
# get ":controller/:action/:id"
|
|
408
456
|
#
|
|
409
|
-
# Two of these symbols are special,
|
|
410
|
-
#
|
|
411
|
-
#
|
|
457
|
+
# Two of these symbols are special, `:controller` maps to the controller and
|
|
458
|
+
# `:action` to the controller's action. A pattern can also map wildcard segments
|
|
459
|
+
# (globs) to params:
|
|
412
460
|
#
|
|
413
|
-
#
|
|
461
|
+
# get 'songs/*category/:title', to: 'songs#show'
|
|
414
462
|
#
|
|
415
|
-
#
|
|
416
|
-
#
|
|
417
|
-
#
|
|
463
|
+
# # 'songs/rock/classic/stairway-to-heaven' sets
|
|
464
|
+
# # params[:category] = 'rock/classic'
|
|
465
|
+
# # params[:title] = 'stairway-to-heaven'
|
|
418
466
|
#
|
|
419
|
-
# To match a wildcard parameter, it must have a name assigned to it.
|
|
420
|
-
#
|
|
421
|
-
# can't be parsed.
|
|
467
|
+
# To match a wildcard parameter, it must have a name assigned to it. Without a
|
|
468
|
+
# variable name to attach the glob parameter to, the route can't be parsed.
|
|
422
469
|
#
|
|
423
|
-
# When a pattern points to an internal route, the route's
|
|
424
|
-
#
|
|
470
|
+
# When a pattern points to an internal route, the route's `:action` and
|
|
471
|
+
# `:controller` should be set in options or hash shorthand. Examples:
|
|
425
472
|
#
|
|
426
|
-
#
|
|
427
|
-
#
|
|
428
|
-
#
|
|
473
|
+
# match 'photos/:id' => 'photos#show', via: :get
|
|
474
|
+
# match 'photos/:id', to: 'photos#show', via: :get
|
|
475
|
+
# match 'photos/:id', controller: 'photos', action: 'show', via: :get
|
|
429
476
|
#
|
|
430
|
-
# A pattern can also point to a
|
|
431
|
-
#
|
|
477
|
+
# A pattern can also point to a `Rack` endpoint i.e. anything that responds to
|
|
478
|
+
# `call`:
|
|
432
479
|
#
|
|
433
|
-
#
|
|
434
|
-
#
|
|
435
|
-
#
|
|
436
|
-
#
|
|
480
|
+
# match 'photos/:id', to: -> (hash) { [200, {}, ["Coming soon"]] }, via: :get
|
|
481
|
+
# match 'photos/:id', to: PhotoRackApp, via: :get
|
|
482
|
+
# # Yes, controller actions are just rack endpoints
|
|
483
|
+
# match 'photos/:id', to: PhotosController.action(:show), via: :get
|
|
437
484
|
#
|
|
438
485
|
# Because requesting various HTTP verbs with a single action has security
|
|
439
|
-
# implications, you must either specify the actions in
|
|
440
|
-
#
|
|
441
|
-
# instead +match+
|
|
486
|
+
# implications, you must either specify the actions in the via options or use
|
|
487
|
+
# one of the [HttpHelpers](rdoc-ref:HttpHelpers) instead `match`
|
|
442
488
|
#
|
|
443
|
-
#
|
|
489
|
+
# ### Options
|
|
444
490
|
#
|
|
445
491
|
# Any options not seen here are passed on as params with the URL.
|
|
446
492
|
#
|
|
447
|
-
#
|
|
448
|
-
# The route's controller.
|
|
493
|
+
# :controller
|
|
494
|
+
# : The route's controller.
|
|
449
495
|
#
|
|
450
|
-
#
|
|
451
|
-
# The route's action.
|
|
496
|
+
# :action
|
|
497
|
+
# : The route's action.
|
|
452
498
|
#
|
|
453
|
-
#
|
|
454
|
-
# Overrides the default resource identifier
|
|
455
|
-
#
|
|
456
|
-
#
|
|
457
|
-
# <tt>params[<:param>]</tt>.
|
|
458
|
-
# In your router:
|
|
499
|
+
# :param
|
|
500
|
+
# : Overrides the default resource identifier `:id` (name of the dynamic
|
|
501
|
+
# segment used to generate the routes). You can access that segment from
|
|
502
|
+
# your controller using `params[<:param>]`. In your router:
|
|
459
503
|
#
|
|
460
|
-
#
|
|
504
|
+
# resources :users, param: :name
|
|
461
505
|
#
|
|
462
|
-
#
|
|
506
|
+
# The `users` resource here will have the following routes generated for it:
|
|
463
507
|
#
|
|
464
|
-
#
|
|
465
|
-
#
|
|
466
|
-
#
|
|
467
|
-
#
|
|
468
|
-
#
|
|
469
|
-
#
|
|
470
|
-
#
|
|
508
|
+
# GET /users(.:format)
|
|
509
|
+
# POST /users(.:format)
|
|
510
|
+
# GET /users/new(.:format)
|
|
511
|
+
# GET /users/:name/edit(.:format)
|
|
512
|
+
# GET /users/:name(.:format)
|
|
513
|
+
# PATCH/PUT /users/:name(.:format)
|
|
514
|
+
# DELETE /users/:name(.:format)
|
|
471
515
|
#
|
|
472
|
-
#
|
|
473
|
-
#
|
|
516
|
+
# You can override `ActiveRecord::Base#to_param` of a related model to
|
|
517
|
+
# construct a URL:
|
|
474
518
|
#
|
|
475
|
-
#
|
|
476
|
-
#
|
|
477
|
-
#
|
|
478
|
-
#
|
|
479
|
-
#
|
|
519
|
+
# class User < ActiveRecord::Base
|
|
520
|
+
# def to_param
|
|
521
|
+
# name
|
|
522
|
+
# end
|
|
523
|
+
# end
|
|
480
524
|
#
|
|
481
|
-
#
|
|
482
|
-
#
|
|
525
|
+
# user = User.find_by(name: 'Phusion')
|
|
526
|
+
# user_path(user) # => "/users/Phusion"
|
|
483
527
|
#
|
|
484
|
-
#
|
|
485
|
-
# The path prefix for the routes.
|
|
528
|
+
# :path
|
|
529
|
+
# : The path prefix for the routes.
|
|
486
530
|
#
|
|
487
|
-
#
|
|
488
|
-
# The namespace for :controller.
|
|
531
|
+
# :module
|
|
532
|
+
# : The namespace for :controller.
|
|
489
533
|
#
|
|
490
|
-
#
|
|
491
|
-
#
|
|
534
|
+
# match 'path', to: 'c#a', module: 'sekret', controller: 'posts', via: :get
|
|
535
|
+
# # => Sekret::PostsController
|
|
492
536
|
#
|
|
493
|
-
#
|
|
537
|
+
# See `Scoping#namespace` for its scope equivalent.
|
|
494
538
|
#
|
|
495
|
-
#
|
|
496
|
-
# The name used to generate routing helpers.
|
|
539
|
+
# :as
|
|
540
|
+
# : The name used to generate routing helpers.
|
|
497
541
|
#
|
|
498
|
-
#
|
|
499
|
-
# Allowed HTTP verb(s) for route.
|
|
542
|
+
# :via
|
|
543
|
+
# : Allowed HTTP verb(s) for route.
|
|
500
544
|
#
|
|
501
|
-
#
|
|
502
|
-
#
|
|
503
|
-
#
|
|
545
|
+
# match 'path', to: 'c#a', via: :get
|
|
546
|
+
# match 'path', to: 'c#a', via: [:get, :post]
|
|
547
|
+
# match 'path', to: 'c#a', via: :all
|
|
504
548
|
#
|
|
505
|
-
#
|
|
506
|
-
# Points to a
|
|
507
|
-
#
|
|
549
|
+
# :to
|
|
550
|
+
# : Points to a `Rack` endpoint. Can be an object that responds to `call` or a
|
|
551
|
+
# string representing a controller's action.
|
|
508
552
|
#
|
|
509
|
-
#
|
|
510
|
-
#
|
|
511
|
-
#
|
|
553
|
+
# match 'path', to: 'controller#action', via: :get
|
|
554
|
+
# match 'path', to: -> (env) { [200, {}, ["Success!"]] }, via: :get
|
|
555
|
+
# match 'path', to: RackApp, via: :get
|
|
512
556
|
#
|
|
513
|
-
#
|
|
514
|
-
# Shorthand for wrapping routes in a specific RESTful context. Valid
|
|
515
|
-
#
|
|
516
|
-
#
|
|
557
|
+
# :on
|
|
558
|
+
# : Shorthand for wrapping routes in a specific RESTful context. Valid values
|
|
559
|
+
# are `:member`, `:collection`, and `:new`. Only use within `resource(s)`
|
|
560
|
+
# block. For example:
|
|
517
561
|
#
|
|
518
|
-
#
|
|
519
|
-
#
|
|
520
|
-
#
|
|
562
|
+
# resource :bar do
|
|
563
|
+
# match 'foo', to: 'c#a', on: :member, via: [:get, :post]
|
|
564
|
+
# end
|
|
521
565
|
#
|
|
522
|
-
#
|
|
566
|
+
# Is equivalent to:
|
|
523
567
|
#
|
|
524
|
-
#
|
|
525
|
-
#
|
|
526
|
-
#
|
|
527
|
-
#
|
|
528
|
-
#
|
|
568
|
+
# resource :bar do
|
|
569
|
+
# member do
|
|
570
|
+
# match 'foo', to: 'c#a', via: [:get, :post]
|
|
571
|
+
# end
|
|
572
|
+
# end
|
|
529
573
|
#
|
|
530
|
-
#
|
|
531
|
-
# Constrains parameters with a hash of regular expressions
|
|
532
|
-
#
|
|
533
|
-
#
|
|
534
|
-
#
|
|
574
|
+
# :constraints
|
|
575
|
+
# : Constrains parameters with a hash of regular expressions or an object that
|
|
576
|
+
# responds to `matches?`. In addition, constraints other than path can also
|
|
577
|
+
# be specified with any object that responds to `===` (e.g. String, Array,
|
|
578
|
+
# Range, etc.).
|
|
535
579
|
#
|
|
536
|
-
#
|
|
580
|
+
# match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: :get
|
|
537
581
|
#
|
|
538
|
-
#
|
|
582
|
+
# match 'json_only', constraints: { format: 'json' }, via: :get
|
|
539
583
|
#
|
|
540
|
-
#
|
|
541
|
-
#
|
|
542
|
-
#
|
|
543
|
-
#
|
|
584
|
+
# class PermitList
|
|
585
|
+
# def matches?(request) request.remote_ip == '1.2.3.4' end
|
|
586
|
+
# end
|
|
587
|
+
# match 'path', to: 'c#a', constraints: PermitList.new, via: :get
|
|
544
588
|
#
|
|
545
|
-
#
|
|
546
|
-
# equivalent.
|
|
589
|
+
# See `Scoping#constraints` for more examples with its scope equivalent.
|
|
547
590
|
#
|
|
548
|
-
#
|
|
549
|
-
# Sets defaults for parameters
|
|
591
|
+
# :defaults
|
|
592
|
+
# : Sets defaults for parameters
|
|
550
593
|
#
|
|
551
|
-
#
|
|
552
|
-
#
|
|
594
|
+
# # Sets params[:format] to 'jpg' by default
|
|
595
|
+
# match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: :get
|
|
553
596
|
#
|
|
554
|
-
#
|
|
597
|
+
# See `Scoping#defaults` for its scope equivalent.
|
|
555
598
|
#
|
|
556
|
-
#
|
|
557
|
-
# Boolean to anchor a
|
|
558
|
-
#
|
|
599
|
+
# :anchor
|
|
600
|
+
# : Boolean to anchor a `match` pattern. Default is true. When set to false,
|
|
601
|
+
# the pattern matches any request prefixed with the given path.
|
|
559
602
|
#
|
|
560
|
-
#
|
|
561
|
-
#
|
|
603
|
+
# # Matches any request starting with 'path'
|
|
604
|
+
# match 'path', to: 'c#a', anchor: false, via: :get
|
|
605
|
+
#
|
|
606
|
+
# :format
|
|
607
|
+
# : Allows you to specify the default value for optional `format` segment or
|
|
608
|
+
# disable it by supplying `false`.
|
|
562
609
|
#
|
|
563
|
-
# [:format]
|
|
564
|
-
# Allows you to specify the default value for optional +format+
|
|
565
|
-
# segment or disable it by supplying +false+.
|
|
566
610
|
def match(path, options = nil)
|
|
567
611
|
end
|
|
568
612
|
|
|
569
613
|
# Mount a Rack-based application to be used within the application.
|
|
570
614
|
#
|
|
571
|
-
#
|
|
615
|
+
# mount SomeRackApp, at: "some_route"
|
|
572
616
|
#
|
|
573
617
|
# Alternatively:
|
|
574
618
|
#
|
|
575
|
-
#
|
|
619
|
+
# mount(SomeRackApp => "some_route")
|
|
576
620
|
#
|
|
577
|
-
# For options, see
|
|
621
|
+
# For options, see `match`, as `mount` uses it internally.
|
|
578
622
|
#
|
|
579
|
-
# All mounted applications come with routing helpers to access them.
|
|
580
|
-
#
|
|
581
|
-
#
|
|
582
|
-
#
|
|
623
|
+
# All mounted applications come with routing helpers to access them. These are
|
|
624
|
+
# named after the class specified, so for the above example the helper is either
|
|
625
|
+
# `some_rack_app_path` or `some_rack_app_url`. To customize this helper's name,
|
|
626
|
+
# use the `:as` option:
|
|
583
627
|
#
|
|
584
|
-
#
|
|
628
|
+
# mount(SomeRackApp => "some_route", as: "exciting")
|
|
585
629
|
#
|
|
586
|
-
# This will generate the
|
|
587
|
-
#
|
|
630
|
+
# This will generate the `exciting_path` and `exciting_url` helpers which can be
|
|
631
|
+
# used to navigate to this mounted app.
|
|
588
632
|
def mount(app, options = nil)
|
|
589
633
|
if options
|
|
590
634
|
path = options.delete(:at)
|
|
@@ -652,13 +696,14 @@ module ActionDispatch
|
|
|
652
696
|
|
|
653
697
|
script_namer = ->(options) do
|
|
654
698
|
prefix_options = options.slice(*_route.segment_keys)
|
|
655
|
-
prefix_options[:
|
|
699
|
+
prefix_options[:script_name] = "" if options[:original_script_name]
|
|
656
700
|
|
|
657
701
|
if options[:_recall]
|
|
658
702
|
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
|
|
659
703
|
end
|
|
660
704
|
|
|
661
|
-
# We must actually delete prefix segment keys to avoid passing them to next
|
|
705
|
+
# We must actually delete prefix segment keys to avoid passing them to next
|
|
706
|
+
# url_for.
|
|
662
707
|
_route.segment_keys.each { |k| options.delete(k) }
|
|
663
708
|
_url_helpers.public_send("#{name}_path", prefix_options)
|
|
664
709
|
end
|
|
@@ -669,7 +714,7 @@ module ActionDispatch
|
|
|
669
714
|
def optimize_routes_generation?; false; end
|
|
670
715
|
|
|
671
716
|
define_method :find_script_name do |options|
|
|
672
|
-
if options.key? :script_name
|
|
717
|
+
if options.key?(:script_name) && options[:script_name].present?
|
|
673
718
|
super(options)
|
|
674
719
|
else
|
|
675
720
|
script_namer.call(options)
|
|
@@ -680,50 +725,50 @@ module ActionDispatch
|
|
|
680
725
|
end
|
|
681
726
|
|
|
682
727
|
module HttpHelpers
|
|
683
|
-
# Define a route that only recognizes HTTP GET.
|
|
684
|
-
#
|
|
728
|
+
# Define a route that only recognizes HTTP GET. For supported arguments, see
|
|
729
|
+
# [match](rdoc-ref:Base#match)
|
|
685
730
|
#
|
|
686
|
-
#
|
|
731
|
+
# get 'bacon', to: 'food#bacon'
|
|
687
732
|
def get(*args, &block)
|
|
688
733
|
map_method(:get, args, &block)
|
|
689
734
|
end
|
|
690
735
|
|
|
691
|
-
# Define a route that only recognizes HTTP POST.
|
|
692
|
-
#
|
|
736
|
+
# Define a route that only recognizes HTTP POST. For supported arguments, see
|
|
737
|
+
# [match](rdoc-ref:Base#match)
|
|
693
738
|
#
|
|
694
|
-
#
|
|
739
|
+
# post 'bacon', to: 'food#bacon'
|
|
695
740
|
def post(*args, &block)
|
|
696
741
|
map_method(:post, args, &block)
|
|
697
742
|
end
|
|
698
743
|
|
|
699
|
-
# Define a route that only recognizes HTTP PATCH.
|
|
700
|
-
#
|
|
744
|
+
# Define a route that only recognizes HTTP PATCH. For supported arguments, see
|
|
745
|
+
# [match](rdoc-ref:Base#match)
|
|
701
746
|
#
|
|
702
|
-
#
|
|
747
|
+
# patch 'bacon', to: 'food#bacon'
|
|
703
748
|
def patch(*args, &block)
|
|
704
749
|
map_method(:patch, args, &block)
|
|
705
750
|
end
|
|
706
751
|
|
|
707
|
-
# Define a route that only recognizes HTTP PUT.
|
|
708
|
-
#
|
|
752
|
+
# Define a route that only recognizes HTTP PUT. For supported arguments, see
|
|
753
|
+
# [match](rdoc-ref:Base#match)
|
|
709
754
|
#
|
|
710
|
-
#
|
|
755
|
+
# put 'bacon', to: 'food#bacon'
|
|
711
756
|
def put(*args, &block)
|
|
712
757
|
map_method(:put, args, &block)
|
|
713
758
|
end
|
|
714
759
|
|
|
715
|
-
# Define a route that only recognizes HTTP DELETE.
|
|
716
|
-
#
|
|
760
|
+
# Define a route that only recognizes HTTP DELETE. For supported arguments, see
|
|
761
|
+
# [match](rdoc-ref:Base#match)
|
|
717
762
|
#
|
|
718
|
-
#
|
|
763
|
+
# delete 'broccoli', to: 'food#broccoli'
|
|
719
764
|
def delete(*args, &block)
|
|
720
765
|
map_method(:delete, args, &block)
|
|
721
766
|
end
|
|
722
767
|
|
|
723
|
-
# Define a route that only recognizes HTTP OPTIONS.
|
|
724
|
-
#
|
|
768
|
+
# Define a route that only recognizes HTTP OPTIONS. For supported arguments, see
|
|
769
|
+
# [match](rdoc-ref:Base#match)
|
|
725
770
|
#
|
|
726
|
-
#
|
|
771
|
+
# options 'carrots', to: 'food#carrots'
|
|
727
772
|
def options(*args, &block)
|
|
728
773
|
map_method(:options, args, &block)
|
|
729
774
|
end
|
|
@@ -737,91 +782,90 @@ module ActionDispatch
|
|
|
737
782
|
end
|
|
738
783
|
end
|
|
739
784
|
|
|
740
|
-
# You may wish to organize groups of controllers under a namespace.
|
|
741
|
-
#
|
|
742
|
-
#
|
|
743
|
-
#
|
|
744
|
-
#
|
|
785
|
+
# You may wish to organize groups of controllers under a namespace. Most
|
|
786
|
+
# commonly, you might group a number of administrative controllers under an
|
|
787
|
+
# `admin` namespace. You would place these controllers under the
|
|
788
|
+
# `app/controllers/admin` directory, and you can group them together in your
|
|
789
|
+
# router:
|
|
745
790
|
#
|
|
746
|
-
#
|
|
747
|
-
#
|
|
748
|
-
#
|
|
791
|
+
# namespace "admin" do
|
|
792
|
+
# resources :posts, :comments
|
|
793
|
+
# end
|
|
749
794
|
#
|
|
750
795
|
# This will create a number of routes for each of the posts and comments
|
|
751
|
-
# controller. For
|
|
796
|
+
# controller. For `Admin::PostsController`, Rails will create:
|
|
752
797
|
#
|
|
753
|
-
#
|
|
754
|
-
#
|
|
755
|
-
#
|
|
756
|
-
#
|
|
757
|
-
#
|
|
758
|
-
#
|
|
759
|
-
#
|
|
798
|
+
# GET /admin/posts
|
|
799
|
+
# GET /admin/posts/new
|
|
800
|
+
# POST /admin/posts
|
|
801
|
+
# GET /admin/posts/1
|
|
802
|
+
# GET /admin/posts/1/edit
|
|
803
|
+
# PATCH/PUT /admin/posts/1
|
|
804
|
+
# DELETE /admin/posts/1
|
|
760
805
|
#
|
|
761
806
|
# If you want to route /posts (without the prefix /admin) to
|
|
762
|
-
#
|
|
807
|
+
# `Admin::PostsController`, you could use
|
|
763
808
|
#
|
|
764
|
-
#
|
|
765
|
-
#
|
|
766
|
-
#
|
|
809
|
+
# scope module: "admin" do
|
|
810
|
+
# resources :posts
|
|
811
|
+
# end
|
|
767
812
|
#
|
|
768
813
|
# or, for a single case
|
|
769
814
|
#
|
|
770
|
-
#
|
|
815
|
+
# resources :posts, module: "admin"
|
|
771
816
|
#
|
|
772
|
-
# If you want to route /admin/posts to
|
|
773
|
-
#
|
|
817
|
+
# If you want to route /admin/posts to `PostsController` (without the `Admin::`
|
|
818
|
+
# module prefix), you could use
|
|
774
819
|
#
|
|
775
|
-
#
|
|
776
|
-
#
|
|
777
|
-
#
|
|
820
|
+
# scope "/admin" do
|
|
821
|
+
# resources :posts
|
|
822
|
+
# end
|
|
778
823
|
#
|
|
779
824
|
# or, for a single case
|
|
780
825
|
#
|
|
781
|
-
#
|
|
826
|
+
# resources :posts, path: "/admin/posts"
|
|
782
827
|
#
|
|
783
|
-
# In each of these cases, the named routes remain the same as if you did
|
|
784
|
-
#
|
|
785
|
-
# +PostsController+:
|
|
828
|
+
# In each of these cases, the named routes remain the same as if you did not use
|
|
829
|
+
# scope. In the last case, the following paths map to `PostsController`:
|
|
786
830
|
#
|
|
787
|
-
#
|
|
788
|
-
#
|
|
789
|
-
#
|
|
790
|
-
#
|
|
791
|
-
#
|
|
792
|
-
#
|
|
793
|
-
#
|
|
831
|
+
# GET /admin/posts
|
|
832
|
+
# GET /admin/posts/new
|
|
833
|
+
# POST /admin/posts
|
|
834
|
+
# GET /admin/posts/1
|
|
835
|
+
# GET /admin/posts/1/edit
|
|
836
|
+
# PATCH/PUT /admin/posts/1
|
|
837
|
+
# DELETE /admin/posts/1
|
|
794
838
|
module Scoping
|
|
795
839
|
# Scopes a set of routes to the given default options.
|
|
796
840
|
#
|
|
797
841
|
# Take the following route definition as an example:
|
|
798
842
|
#
|
|
799
|
-
#
|
|
800
|
-
#
|
|
801
|
-
#
|
|
843
|
+
# scope path: ":account_id", as: "account" do
|
|
844
|
+
# resources :projects
|
|
845
|
+
# end
|
|
802
846
|
#
|
|
803
|
-
# This generates helpers such as
|
|
804
|
-
# The difference here being that the routes generated are like
|
|
805
|
-
# rather than /accounts/:account_id/projects.
|
|
847
|
+
# This generates helpers such as `account_projects_path`, just like `resources`
|
|
848
|
+
# does. The difference here being that the routes generated are like
|
|
849
|
+
# /:account_id/projects, rather than /accounts/:account_id/projects.
|
|
806
850
|
#
|
|
807
|
-
#
|
|
851
|
+
# ### Options
|
|
808
852
|
#
|
|
809
|
-
# Takes same options as
|
|
853
|
+
# Takes same options as `Base#match` and `Resources#resources`.
|
|
810
854
|
#
|
|
811
|
-
#
|
|
812
|
-
#
|
|
813
|
-
#
|
|
814
|
-
#
|
|
855
|
+
# # route /posts (without the prefix /admin) to +Admin::PostsController+
|
|
856
|
+
# scope module: "admin" do
|
|
857
|
+
# resources :posts
|
|
858
|
+
# end
|
|
815
859
|
#
|
|
816
|
-
#
|
|
817
|
-
#
|
|
818
|
-
#
|
|
819
|
-
#
|
|
860
|
+
# # prefix the posts resource's requests with '/admin'
|
|
861
|
+
# scope path: "/admin" do
|
|
862
|
+
# resources :posts
|
|
863
|
+
# end
|
|
820
864
|
#
|
|
821
|
-
#
|
|
822
|
-
#
|
|
823
|
-
#
|
|
824
|
-
#
|
|
865
|
+
# # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
|
|
866
|
+
# scope as: "sekret" do
|
|
867
|
+
# resources :posts
|
|
868
|
+
# end
|
|
825
869
|
def scope(*args)
|
|
826
870
|
options = args.extract_options!.dup
|
|
827
871
|
scope = {}
|
|
@@ -878,9 +922,9 @@ module ActionDispatch
|
|
|
878
922
|
|
|
879
923
|
# Scopes routes to a specific controller
|
|
880
924
|
#
|
|
881
|
-
#
|
|
882
|
-
#
|
|
883
|
-
#
|
|
925
|
+
# controller "food" do
|
|
926
|
+
# match "bacon", action: :bacon, via: :get
|
|
927
|
+
# end
|
|
884
928
|
def controller(controller)
|
|
885
929
|
@scope = @scope.new(controller: controller)
|
|
886
930
|
yield
|
|
@@ -890,42 +934,42 @@ module ActionDispatch
|
|
|
890
934
|
|
|
891
935
|
# Scopes routes to a specific namespace. For example:
|
|
892
936
|
#
|
|
893
|
-
#
|
|
894
|
-
#
|
|
895
|
-
#
|
|
937
|
+
# namespace :admin do
|
|
938
|
+
# resources :posts
|
|
939
|
+
# end
|
|
896
940
|
#
|
|
897
941
|
# This generates the following routes:
|
|
898
942
|
#
|
|
899
|
-
#
|
|
900
|
-
#
|
|
901
|
-
#
|
|
902
|
-
#
|
|
903
|
-
#
|
|
904
|
-
#
|
|
905
|
-
#
|
|
943
|
+
# admin_posts GET /admin/posts(.:format) admin/posts#index
|
|
944
|
+
# admin_posts POST /admin/posts(.:format) admin/posts#create
|
|
945
|
+
# new_admin_post GET /admin/posts/new(.:format) admin/posts#new
|
|
946
|
+
# edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
|
|
947
|
+
# admin_post GET /admin/posts/:id(.:format) admin/posts#show
|
|
948
|
+
# admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
|
|
949
|
+
# admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
|
|
906
950
|
#
|
|
907
|
-
#
|
|
951
|
+
# ### Options
|
|
908
952
|
#
|
|
909
|
-
# The
|
|
910
|
-
#
|
|
953
|
+
# The `:path`, `:as`, `:module`, `:shallow_path`, and `:shallow_prefix` options
|
|
954
|
+
# all default to the name of the namespace.
|
|
911
955
|
#
|
|
912
|
-
# For options, see
|
|
913
|
-
#
|
|
956
|
+
# For options, see `Base#match`. For `:shallow_path` option, see
|
|
957
|
+
# `Resources#resources`.
|
|
914
958
|
#
|
|
915
|
-
#
|
|
916
|
-
#
|
|
917
|
-
#
|
|
918
|
-
#
|
|
959
|
+
# # accessible through /sekret/posts rather than /admin/posts
|
|
960
|
+
# namespace :admin, path: "sekret" do
|
|
961
|
+
# resources :posts
|
|
962
|
+
# end
|
|
919
963
|
#
|
|
920
|
-
#
|
|
921
|
-
#
|
|
922
|
-
#
|
|
923
|
-
#
|
|
964
|
+
# # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
|
|
965
|
+
# namespace :admin, module: "sekret" do
|
|
966
|
+
# resources :posts
|
|
967
|
+
# end
|
|
924
968
|
#
|
|
925
|
-
#
|
|
926
|
-
#
|
|
927
|
-
#
|
|
928
|
-
#
|
|
969
|
+
# # generates +sekret_posts_path+ rather than +admin_posts_path+
|
|
970
|
+
# namespace :admin, as: "sekret" do
|
|
971
|
+
# resources :posts
|
|
972
|
+
# end
|
|
929
973
|
def namespace(path, options = {}, &block)
|
|
930
974
|
path = path.to_s
|
|
931
975
|
|
|
@@ -941,70 +985,74 @@ module ActionDispatch
|
|
|
941
985
|
end
|
|
942
986
|
end
|
|
943
987
|
|
|
944
|
-
#
|
|
945
|
-
# Allows you to constrain the nested routes based on a set of rules.
|
|
946
|
-
#
|
|
988
|
+
# ### Parameter Restriction
|
|
989
|
+
# Allows you to constrain the nested routes based on a set of rules. For
|
|
990
|
+
# instance, in order to change the routes to allow for a dot character in the
|
|
991
|
+
# `id` parameter:
|
|
947
992
|
#
|
|
948
|
-
#
|
|
949
|
-
#
|
|
950
|
-
#
|
|
993
|
+
# constraints(id: /\d+\.\d+/) do
|
|
994
|
+
# resources :posts
|
|
995
|
+
# end
|
|
951
996
|
#
|
|
952
|
-
# Now routes such as
|
|
953
|
-
# The
|
|
997
|
+
# Now routes such as `/posts/1` will no longer be valid, but `/posts/1.1` will
|
|
998
|
+
# be. The `id` parameter must match the constraint passed in for this example.
|
|
954
999
|
#
|
|
955
1000
|
# You may use this to also restrict other parameters:
|
|
956
1001
|
#
|
|
957
|
-
#
|
|
958
|
-
#
|
|
959
|
-
#
|
|
1002
|
+
# resources :posts do
|
|
1003
|
+
# constraints(post_id: /\d+\.\d+/) do
|
|
1004
|
+
# resources :comments
|
|
1005
|
+
# end
|
|
960
1006
|
# end
|
|
961
|
-
# end
|
|
962
1007
|
#
|
|
963
|
-
#
|
|
1008
|
+
# ### Restricting based on IP
|
|
964
1009
|
#
|
|
965
1010
|
# Routes can also be constrained to an IP or a certain range of IP addresses:
|
|
966
1011
|
#
|
|
967
|
-
#
|
|
968
|
-
#
|
|
969
|
-
#
|
|
1012
|
+
# constraints(ip: /192\.168\.\d+\.\d+/) do
|
|
1013
|
+
# resources :posts
|
|
1014
|
+
# end
|
|
970
1015
|
#
|
|
971
|
-
# Any user connecting from the 192.168.* range will be able to see this
|
|
972
|
-
# where as any user connecting outside of this range will be told
|
|
1016
|
+
# Any user connecting from the 192.168.* range will be able to see this
|
|
1017
|
+
# resource, where as any user connecting outside of this range will be told
|
|
1018
|
+
# there is no such route.
|
|
973
1019
|
#
|
|
974
|
-
#
|
|
1020
|
+
# ### Dynamic request matching
|
|
975
1021
|
#
|
|
976
1022
|
# Requests to routes can be constrained based on specific criteria:
|
|
977
1023
|
#
|
|
978
|
-
#
|
|
979
|
-
#
|
|
980
|
-
#
|
|
1024
|
+
# constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
|
|
1025
|
+
# resources :iphones
|
|
1026
|
+
# end
|
|
981
1027
|
#
|
|
982
|
-
# You are able to move this logic out into a class if it is too complex for
|
|
983
|
-
# This class must have a
|
|
984
|
-
# if the user should be given access to that route, or
|
|
1028
|
+
# You are able to move this logic out into a class if it is too complex for
|
|
1029
|
+
# routes. This class must have a `matches?` method defined on it which either
|
|
1030
|
+
# returns `true` if the user should be given access to that route, or `false` if
|
|
1031
|
+
# the user should not.
|
|
985
1032
|
#
|
|
986
|
-
#
|
|
987
|
-
#
|
|
988
|
-
#
|
|
989
|
-
#
|
|
990
|
-
#
|
|
1033
|
+
# class Iphone
|
|
1034
|
+
# def self.matches?(request)
|
|
1035
|
+
# /iPhone/.match?(request.env["HTTP_USER_AGENT"])
|
|
1036
|
+
# end
|
|
1037
|
+
# end
|
|
991
1038
|
#
|
|
992
|
-
# An expected place for this code would be
|
|
1039
|
+
# An expected place for this code would be `lib/constraints`.
|
|
993
1040
|
#
|
|
994
1041
|
# This class is then used like this:
|
|
995
1042
|
#
|
|
996
|
-
#
|
|
997
|
-
#
|
|
998
|
-
#
|
|
1043
|
+
# constraints(Iphone) do
|
|
1044
|
+
# resources :iphones
|
|
1045
|
+
# end
|
|
999
1046
|
def constraints(constraints = {}, &block)
|
|
1000
1047
|
scope(constraints: constraints, &block)
|
|
1001
1048
|
end
|
|
1002
1049
|
|
|
1003
1050
|
# Allows you to set default parameters for a route, such as this:
|
|
1004
|
-
#
|
|
1005
|
-
#
|
|
1006
|
-
#
|
|
1007
|
-
#
|
|
1051
|
+
# defaults id: 'home' do
|
|
1052
|
+
# match 'scoped_pages/(:id)', to: 'pages#show'
|
|
1053
|
+
# end
|
|
1054
|
+
#
|
|
1055
|
+
# Using this, the `:id` parameter here will default to 'home'.
|
|
1008
1056
|
def defaults(defaults = {})
|
|
1009
1057
|
@scope = @scope.new(defaults: merge_defaults_scope(@scope[:defaults], defaults))
|
|
1010
1058
|
yield
|
|
@@ -1080,48 +1128,46 @@ module ActionDispatch
|
|
|
1080
1128
|
end
|
|
1081
1129
|
end
|
|
1082
1130
|
|
|
1083
|
-
# Resource routing allows you to quickly declare all of the common routes
|
|
1084
|
-
#
|
|
1085
|
-
#
|
|
1086
|
-
#
|
|
1131
|
+
# Resource routing allows you to quickly declare all of the common routes for a
|
|
1132
|
+
# given resourceful controller. Instead of declaring separate routes for your
|
|
1133
|
+
# `index`, `show`, `new`, `edit`, `create`, `update`, and `destroy` actions, a
|
|
1134
|
+
# resourceful route declares them in a single line of code:
|
|
1087
1135
|
#
|
|
1088
|
-
#
|
|
1136
|
+
# resources :photos
|
|
1089
1137
|
#
|
|
1090
|
-
# Sometimes, you have a resource that clients always look up without
|
|
1091
|
-
#
|
|
1092
|
-
#
|
|
1093
|
-
#
|
|
1138
|
+
# Sometimes, you have a resource that clients always look up without referencing
|
|
1139
|
+
# an ID. A common example, /profile always shows the profile of the currently
|
|
1140
|
+
# logged in user. In this case, you can use a singular resource to map /profile
|
|
1141
|
+
# (rather than /profile/:id) to the show action.
|
|
1094
1142
|
#
|
|
1095
|
-
#
|
|
1143
|
+
# resource :profile
|
|
1096
1144
|
#
|
|
1097
|
-
# It's common to have resources that are logically children of other
|
|
1098
|
-
# resources:
|
|
1145
|
+
# It's common to have resources that are logically children of other resources:
|
|
1099
1146
|
#
|
|
1100
|
-
#
|
|
1101
|
-
#
|
|
1102
|
-
#
|
|
1147
|
+
# resources :magazines do
|
|
1148
|
+
# resources :ads
|
|
1149
|
+
# end
|
|
1103
1150
|
#
|
|
1104
1151
|
# You may wish to organize groups of controllers under a namespace. Most
|
|
1105
|
-
# commonly, you might group a number of administrative controllers under
|
|
1106
|
-
#
|
|
1107
|
-
#
|
|
1108
|
-
#
|
|
1152
|
+
# commonly, you might group a number of administrative controllers under an
|
|
1153
|
+
# `admin` namespace. You would place these controllers under the
|
|
1154
|
+
# `app/controllers/admin` directory, and you can group them together in your
|
|
1155
|
+
# router:
|
|
1109
1156
|
#
|
|
1110
|
-
#
|
|
1111
|
-
#
|
|
1112
|
-
#
|
|
1157
|
+
# namespace "admin" do
|
|
1158
|
+
# resources :posts, :comments
|
|
1159
|
+
# end
|
|
1113
1160
|
#
|
|
1114
|
-
# By default the
|
|
1115
|
-
#
|
|
1116
|
-
#
|
|
1161
|
+
# By default the `:id` parameter doesn't accept dots. If you need to use dots as
|
|
1162
|
+
# part of the `:id` parameter add a constraint which overrides this restriction,
|
|
1163
|
+
# e.g:
|
|
1117
1164
|
#
|
|
1118
|
-
#
|
|
1119
|
-
#
|
|
1120
|
-
# This allows any character other than a slash as part of your +:id+.
|
|
1165
|
+
# resources :articles, id: /[^\/]+/
|
|
1121
1166
|
#
|
|
1167
|
+
# This allows any character other than a slash as part of your `:id`.
|
|
1122
1168
|
module Resources
|
|
1123
|
-
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
|
|
1124
|
-
#
|
|
1169
|
+
# CANONICAL_ACTIONS holds all actions that does not need a prefix or a path
|
|
1170
|
+
# appended since they fit properly in their scope level.
|
|
1125
1171
|
VALID_ON_OPTIONS = [:new, :collection, :member]
|
|
1126
1172
|
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
|
1127
1173
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
|
@@ -1184,8 +1230,8 @@ module ActionDispatch
|
|
|
1184
1230
|
|
|
1185
1231
|
alias :member_name :singular
|
|
1186
1232
|
|
|
1187
|
-
# Checks for uncountable plurals, and appends "_index" if the plural
|
|
1188
|
-
#
|
|
1233
|
+
# Checks for uncountable plurals, and appends "_index" if the plural and
|
|
1234
|
+
# singular form are the same.
|
|
1189
1235
|
def collection_name
|
|
1190
1236
|
singular == plural ? "#{plural}_index" : plural
|
|
1191
1237
|
end
|
|
@@ -1258,37 +1304,35 @@ module ActionDispatch
|
|
|
1258
1304
|
@scope[:path_names].merge!(options)
|
|
1259
1305
|
end
|
|
1260
1306
|
|
|
1261
|
-
# Sometimes, you have a resource that clients always look up without
|
|
1262
|
-
#
|
|
1263
|
-
#
|
|
1264
|
-
#
|
|
1265
|
-
# the show action:
|
|
1307
|
+
# Sometimes, you have a resource that clients always look up without referencing
|
|
1308
|
+
# an ID. A common example, /profile always shows the profile of the currently
|
|
1309
|
+
# logged in user. In this case, you can use a singular resource to map /profile
|
|
1310
|
+
# (rather than /profile/:id) to the show action:
|
|
1266
1311
|
#
|
|
1267
|
-
#
|
|
1312
|
+
# resource :profile
|
|
1268
1313
|
#
|
|
1269
|
-
# This creates six different routes in your application, all mapping to
|
|
1270
|
-
#
|
|
1271
|
-
# the plural):
|
|
1314
|
+
# This creates six different routes in your application, all mapping to the
|
|
1315
|
+
# `Profiles` controller (note that the controller is named after the plural):
|
|
1272
1316
|
#
|
|
1273
|
-
#
|
|
1274
|
-
#
|
|
1275
|
-
#
|
|
1276
|
-
#
|
|
1277
|
-
#
|
|
1278
|
-
#
|
|
1317
|
+
# GET /profile/new
|
|
1318
|
+
# GET /profile
|
|
1319
|
+
# GET /profile/edit
|
|
1320
|
+
# PATCH/PUT /profile
|
|
1321
|
+
# DELETE /profile
|
|
1322
|
+
# POST /profile
|
|
1279
1323
|
#
|
|
1280
|
-
# If you want instances of a model to work with this resource via
|
|
1281
|
-
#
|
|
1282
|
-
#
|
|
1324
|
+
# If you want instances of a model to work with this resource via record
|
|
1325
|
+
# identification (e.g. in `form_with` or `redirect_to`), you will need to call
|
|
1326
|
+
# [resolve](rdoc-ref:CustomUrls#resolve):
|
|
1283
1327
|
#
|
|
1284
|
-
#
|
|
1285
|
-
#
|
|
1328
|
+
# resource :profile
|
|
1329
|
+
# resolve('Profile') { [:profile] }
|
|
1286
1330
|
#
|
|
1287
|
-
#
|
|
1288
|
-
#
|
|
1331
|
+
# # Enables this to work with singular routes:
|
|
1332
|
+
# form_with(model: @profile) {}
|
|
1289
1333
|
#
|
|
1290
|
-
#
|
|
1291
|
-
# Takes same options as resources
|
|
1334
|
+
# ### Options
|
|
1335
|
+
# Takes same options as [resources](rdoc-ref:#resources)
|
|
1292
1336
|
def resource(*resources, &block)
|
|
1293
1337
|
options = resources.extract_options!.dup
|
|
1294
1338
|
|
|
@@ -1318,143 +1362,147 @@ module ActionDispatch
|
|
|
1318
1362
|
self
|
|
1319
1363
|
end
|
|
1320
1364
|
|
|
1321
|
-
# In Rails, a resourceful route provides a mapping between HTTP verbs
|
|
1322
|
-
# and
|
|
1323
|
-
#
|
|
1324
|
-
# routing file, such as
|
|
1365
|
+
# In Rails, a resourceful route provides a mapping between HTTP verbs and URLs
|
|
1366
|
+
# and controller actions. By convention, each action also maps to particular
|
|
1367
|
+
# CRUD operations in a database. A single entry in the routing file, such as
|
|
1325
1368
|
#
|
|
1326
|
-
#
|
|
1369
|
+
# resources :photos
|
|
1327
1370
|
#
|
|
1328
|
-
# creates seven different routes in your application, all mapping to
|
|
1329
|
-
#
|
|
1371
|
+
# creates seven different routes in your application, all mapping to the
|
|
1372
|
+
# `Photos` controller:
|
|
1330
1373
|
#
|
|
1331
|
-
#
|
|
1332
|
-
#
|
|
1333
|
-
#
|
|
1334
|
-
#
|
|
1335
|
-
#
|
|
1336
|
-
#
|
|
1337
|
-
#
|
|
1374
|
+
# GET /photos
|
|
1375
|
+
# GET /photos/new
|
|
1376
|
+
# POST /photos
|
|
1377
|
+
# GET /photos/:id
|
|
1378
|
+
# GET /photos/:id/edit
|
|
1379
|
+
# PATCH/PUT /photos/:id
|
|
1380
|
+
# DELETE /photos/:id
|
|
1338
1381
|
#
|
|
1339
1382
|
# Resources can also be nested infinitely by using this block syntax:
|
|
1340
1383
|
#
|
|
1341
|
-
#
|
|
1342
|
-
#
|
|
1343
|
-
#
|
|
1384
|
+
# resources :photos do
|
|
1385
|
+
# resources :comments
|
|
1386
|
+
# end
|
|
1344
1387
|
#
|
|
1345
1388
|
# This generates the following comments routes:
|
|
1346
1389
|
#
|
|
1347
|
-
#
|
|
1348
|
-
#
|
|
1349
|
-
#
|
|
1350
|
-
#
|
|
1351
|
-
#
|
|
1352
|
-
#
|
|
1353
|
-
#
|
|
1390
|
+
# GET /photos/:photo_id/comments
|
|
1391
|
+
# GET /photos/:photo_id/comments/new
|
|
1392
|
+
# POST /photos/:photo_id/comments
|
|
1393
|
+
# GET /photos/:photo_id/comments/:id
|
|
1394
|
+
# GET /photos/:photo_id/comments/:id/edit
|
|
1395
|
+
# PATCH/PUT /photos/:photo_id/comments/:id
|
|
1396
|
+
# DELETE /photos/:photo_id/comments/:id
|
|
1354
1397
|
#
|
|
1355
|
-
#
|
|
1356
|
-
# Takes same options as match
|
|
1398
|
+
# ### Options
|
|
1399
|
+
# Takes same options as [match](rdoc-ref:Base#match) as well as:
|
|
1357
1400
|
#
|
|
1358
|
-
#
|
|
1359
|
-
# Allows you to change the segment component of the
|
|
1360
|
-
#
|
|
1401
|
+
# :path_names
|
|
1402
|
+
# : Allows you to change the segment component of the `edit` and `new`
|
|
1403
|
+
# actions. Actions not specified are not changed.
|
|
1361
1404
|
#
|
|
1362
|
-
#
|
|
1405
|
+
# resources :posts, path_names: { new: "brand_new" }
|
|
1363
1406
|
#
|
|
1364
|
-
#
|
|
1407
|
+
# The above example will now change /posts/new to /posts/brand_new.
|
|
1365
1408
|
#
|
|
1366
|
-
#
|
|
1367
|
-
# Allows you to change the path prefix for the resource.
|
|
1409
|
+
# :path
|
|
1410
|
+
# : Allows you to change the path prefix for the resource.
|
|
1368
1411
|
#
|
|
1369
|
-
#
|
|
1412
|
+
# resources :posts, path: 'postings'
|
|
1370
1413
|
#
|
|
1371
|
-
#
|
|
1414
|
+
# The resource and all segments will now route to /postings instead of
|
|
1415
|
+
# /posts.
|
|
1372
1416
|
#
|
|
1373
|
-
#
|
|
1374
|
-
# Only generate routes for the given actions.
|
|
1417
|
+
# :only
|
|
1418
|
+
# : Only generate routes for the given actions.
|
|
1375
1419
|
#
|
|
1376
|
-
#
|
|
1377
|
-
#
|
|
1420
|
+
# resources :cows, only: :show
|
|
1421
|
+
# resources :cows, only: [:show, :index]
|
|
1378
1422
|
#
|
|
1379
|
-
#
|
|
1380
|
-
# Generate all routes except for the given actions.
|
|
1423
|
+
# :except
|
|
1424
|
+
# : Generate all routes except for the given actions.
|
|
1381
1425
|
#
|
|
1382
|
-
#
|
|
1383
|
-
#
|
|
1426
|
+
# resources :cows, except: :show
|
|
1427
|
+
# resources :cows, except: [:show, :index]
|
|
1384
1428
|
#
|
|
1385
|
-
#
|
|
1386
|
-
# Generates shallow routes for nested resource(s). When placed on a parent
|
|
1387
|
-
#
|
|
1429
|
+
# :shallow
|
|
1430
|
+
# : Generates shallow routes for nested resource(s). When placed on a parent
|
|
1431
|
+
# resource, generates shallow routes for all nested resources.
|
|
1388
1432
|
#
|
|
1389
|
-
#
|
|
1390
|
-
#
|
|
1391
|
-
#
|
|
1433
|
+
# resources :posts, shallow: true do
|
|
1434
|
+
# resources :comments
|
|
1435
|
+
# end
|
|
1392
1436
|
#
|
|
1393
|
-
#
|
|
1437
|
+
# Is the same as:
|
|
1394
1438
|
#
|
|
1395
|
-
#
|
|
1396
|
-
#
|
|
1397
|
-
#
|
|
1398
|
-
#
|
|
1439
|
+
# resources :posts do
|
|
1440
|
+
# resources :comments, except: [:show, :edit, :update, :destroy]
|
|
1441
|
+
# end
|
|
1442
|
+
# resources :comments, only: [:show, :edit, :update, :destroy]
|
|
1399
1443
|
#
|
|
1400
|
-
#
|
|
1401
|
-
#
|
|
1402
|
-
#
|
|
1444
|
+
# This allows URLs for resources that otherwise would be deeply nested such
|
|
1445
|
+
# as a comment on a blog post like `/posts/a-long-permalink/comments/1234`
|
|
1446
|
+
# to be shortened to just `/comments/1234`.
|
|
1403
1447
|
#
|
|
1404
|
-
#
|
|
1448
|
+
# Set `shallow: false` on a child resource to ignore a parent's shallow
|
|
1449
|
+
# parameter.
|
|
1405
1450
|
#
|
|
1406
|
-
#
|
|
1407
|
-
# Prefixes nested shallow routes with the specified path.
|
|
1451
|
+
# :shallow_path
|
|
1452
|
+
# : Prefixes nested shallow routes with the specified path.
|
|
1408
1453
|
#
|
|
1409
|
-
#
|
|
1410
|
-
#
|
|
1411
|
-
#
|
|
1412
|
-
#
|
|
1413
|
-
#
|
|
1454
|
+
# scope shallow_path: "sekret" do
|
|
1455
|
+
# resources :posts do
|
|
1456
|
+
# resources :comments, shallow: true
|
|
1457
|
+
# end
|
|
1458
|
+
# end
|
|
1414
1459
|
#
|
|
1415
|
-
#
|
|
1460
|
+
# The `comments` resource here will have the following routes generated for
|
|
1461
|
+
# it:
|
|
1416
1462
|
#
|
|
1417
|
-
#
|
|
1418
|
-
#
|
|
1419
|
-
#
|
|
1420
|
-
#
|
|
1421
|
-
#
|
|
1422
|
-
#
|
|
1423
|
-
#
|
|
1463
|
+
# post_comments GET /posts/:post_id/comments(.:format)
|
|
1464
|
+
# post_comments POST /posts/:post_id/comments(.:format)
|
|
1465
|
+
# new_post_comment GET /posts/:post_id/comments/new(.:format)
|
|
1466
|
+
# edit_comment GET /sekret/comments/:id/edit(.:format)
|
|
1467
|
+
# comment GET /sekret/comments/:id(.:format)
|
|
1468
|
+
# comment PATCH/PUT /sekret/comments/:id(.:format)
|
|
1469
|
+
# comment DELETE /sekret/comments/:id(.:format)
|
|
1424
1470
|
#
|
|
1425
|
-
#
|
|
1426
|
-
# Prefixes nested shallow route names with specified prefix.
|
|
1471
|
+
# :shallow_prefix
|
|
1472
|
+
# : Prefixes nested shallow route names with specified prefix.
|
|
1427
1473
|
#
|
|
1428
|
-
#
|
|
1429
|
-
#
|
|
1430
|
-
#
|
|
1431
|
-
#
|
|
1432
|
-
#
|
|
1474
|
+
# scope shallow_prefix: "sekret" do
|
|
1475
|
+
# resources :posts do
|
|
1476
|
+
# resources :comments, shallow: true
|
|
1477
|
+
# end
|
|
1478
|
+
# end
|
|
1433
1479
|
#
|
|
1434
|
-
#
|
|
1480
|
+
# The `comments` resource here will have the following routes generated for
|
|
1481
|
+
# it:
|
|
1435
1482
|
#
|
|
1436
|
-
#
|
|
1437
|
-
#
|
|
1438
|
-
#
|
|
1439
|
-
#
|
|
1440
|
-
#
|
|
1441
|
-
#
|
|
1442
|
-
#
|
|
1483
|
+
# post_comments GET /posts/:post_id/comments(.:format)
|
|
1484
|
+
# post_comments POST /posts/:post_id/comments(.:format)
|
|
1485
|
+
# new_post_comment GET /posts/:post_id/comments/new(.:format)
|
|
1486
|
+
# edit_sekret_comment GET /comments/:id/edit(.:format)
|
|
1487
|
+
# sekret_comment GET /comments/:id(.:format)
|
|
1488
|
+
# sekret_comment PATCH/PUT /comments/:id(.:format)
|
|
1489
|
+
# sekret_comment DELETE /comments/:id(.:format)
|
|
1443
1490
|
#
|
|
1444
|
-
#
|
|
1445
|
-
# Allows you to specify the default value for optional
|
|
1446
|
-
#
|
|
1491
|
+
# :format
|
|
1492
|
+
# : Allows you to specify the default value for optional `format` segment or
|
|
1493
|
+
# disable it by supplying `false`.
|
|
1447
1494
|
#
|
|
1448
|
-
#
|
|
1449
|
-
# Allows you to override the default param name of
|
|
1495
|
+
# :param
|
|
1496
|
+
# : Allows you to override the default param name of `:id` in the URL.
|
|
1450
1497
|
#
|
|
1451
|
-
# === Examples
|
|
1452
1498
|
#
|
|
1453
|
-
#
|
|
1454
|
-
# resources :posts, module: "admin"
|
|
1499
|
+
# ### Examples
|
|
1455
1500
|
#
|
|
1456
|
-
#
|
|
1457
|
-
#
|
|
1501
|
+
# # routes call +Admin::PostsController+
|
|
1502
|
+
# resources :posts, module: "admin"
|
|
1503
|
+
#
|
|
1504
|
+
# # resource actions are at /admin/posts.
|
|
1505
|
+
# resources :posts, path: "admin/posts"
|
|
1458
1506
|
def resources(*resources, &block)
|
|
1459
1507
|
options = resources.extract_options!.dup
|
|
1460
1508
|
|
|
@@ -1487,16 +1535,15 @@ module ActionDispatch
|
|
|
1487
1535
|
|
|
1488
1536
|
# To add a route to the collection:
|
|
1489
1537
|
#
|
|
1490
|
-
#
|
|
1491
|
-
#
|
|
1492
|
-
#
|
|
1538
|
+
# resources :photos do
|
|
1539
|
+
# collection do
|
|
1540
|
+
# get 'search'
|
|
1541
|
+
# end
|
|
1493
1542
|
# end
|
|
1494
|
-
# end
|
|
1495
1543
|
#
|
|
1496
|
-
# This will enable Rails to recognize paths such as
|
|
1497
|
-
#
|
|
1498
|
-
#
|
|
1499
|
-
# route helpers.
|
|
1544
|
+
# This will enable Rails to recognize paths such as `/photos/search` with GET,
|
|
1545
|
+
# and route to the search action of `PhotosController`. It will also create the
|
|
1546
|
+
# `search_photos_url` and `search_photos_path` route helpers.
|
|
1500
1547
|
def collection(&block)
|
|
1501
1548
|
unless resource_scope?
|
|
1502
1549
|
raise ArgumentError, "can't use collection outside resource(s) scope"
|
|
@@ -1509,15 +1556,15 @@ module ActionDispatch
|
|
|
1509
1556
|
|
|
1510
1557
|
# To add a member route, add a member block into the resource block:
|
|
1511
1558
|
#
|
|
1512
|
-
#
|
|
1513
|
-
#
|
|
1514
|
-
#
|
|
1559
|
+
# resources :photos do
|
|
1560
|
+
# member do
|
|
1561
|
+
# get 'preview'
|
|
1562
|
+
# end
|
|
1515
1563
|
# end
|
|
1516
|
-
# end
|
|
1517
1564
|
#
|
|
1518
|
-
# This will recognize
|
|
1519
|
-
#
|
|
1520
|
-
#
|
|
1565
|
+
# This will recognize `/photos/1/preview` with GET, and route to the preview
|
|
1566
|
+
# action of `PhotosController`. It will also create the `preview_photo_url` and
|
|
1567
|
+
# `preview_photo_path` helpers.
|
|
1521
1568
|
def member(&block)
|
|
1522
1569
|
unless resource_scope?
|
|
1523
1570
|
raise ArgumentError, "can't use member outside resource(s) scope"
|
|
@@ -1584,29 +1631,28 @@ module ActionDispatch
|
|
|
1584
1631
|
!parent_resource.singleton? && @scope[:shallow]
|
|
1585
1632
|
end
|
|
1586
1633
|
|
|
1587
|
-
# Loads another routes file with the given
|
|
1588
|
-
#
|
|
1589
|
-
#
|
|
1590
|
-
#
|
|
1591
|
-
#
|
|
1592
|
-
#
|
|
1593
|
-
#
|
|
1594
|
-
#
|
|
1595
|
-
#
|
|
1596
|
-
#
|
|
1597
|
-
#
|
|
1598
|
-
#
|
|
1599
|
-
#
|
|
1600
|
-
#
|
|
1601
|
-
#
|
|
1602
|
-
#
|
|
1603
|
-
#
|
|
1604
|
-
#
|
|
1605
|
-
#
|
|
1606
|
-
#
|
|
1607
|
-
#
|
|
1608
|
-
#
|
|
1609
|
-
# developers to have a single routes file.
|
|
1634
|
+
# Loads another routes file with the given `name` located inside the
|
|
1635
|
+
# `config/routes` directory. In that file, you can use the normal routing DSL,
|
|
1636
|
+
# but *do not* surround it with a `Rails.application.routes.draw` block.
|
|
1637
|
+
#
|
|
1638
|
+
# # config/routes.rb
|
|
1639
|
+
# Rails.application.routes.draw do
|
|
1640
|
+
# draw :admin # Loads `config/routes/admin.rb`
|
|
1641
|
+
# draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb`
|
|
1642
|
+
# end
|
|
1643
|
+
#
|
|
1644
|
+
# # config/routes/admin.rb
|
|
1645
|
+
# namespace :admin do
|
|
1646
|
+
# resources :accounts
|
|
1647
|
+
# end
|
|
1648
|
+
#
|
|
1649
|
+
# # config/routes/third_party/some_gem.rb
|
|
1650
|
+
# mount SomeGem::Engine, at: "/some_gem"
|
|
1651
|
+
#
|
|
1652
|
+
# **CAUTION:** Use this feature with care. Having multiple routes files can
|
|
1653
|
+
# negatively impact discoverability and readability. For most applications —
|
|
1654
|
+
# even those with a few hundred routes — it's easier for developers to have a
|
|
1655
|
+
# single routes file.
|
|
1610
1656
|
def draw(name)
|
|
1611
1657
|
path = @draw_paths.find do |_path|
|
|
1612
1658
|
File.exist? "#{_path}/#{name}.rb"
|
|
@@ -1623,12 +1669,12 @@ module ActionDispatch
|
|
|
1623
1669
|
instance_eval(File.read(route_path), route_path.to_s)
|
|
1624
1670
|
end
|
|
1625
1671
|
|
|
1626
|
-
# Matches a URL pattern to one or more routes.
|
|
1627
|
-
#
|
|
1672
|
+
# Matches a URL pattern to one or more routes. For more information, see
|
|
1673
|
+
# [match](rdoc-ref:Base#match).
|
|
1628
1674
|
#
|
|
1629
|
-
#
|
|
1630
|
-
#
|
|
1631
|
-
#
|
|
1675
|
+
# match 'path' => 'controller#action', via: :patch
|
|
1676
|
+
# match 'path', to: 'controller#action', via: :post
|
|
1677
|
+
# match 'path', 'otherpath', on: :member, via: :get
|
|
1632
1678
|
def match(path, *rest, &block)
|
|
1633
1679
|
if rest.empty? && Hash === path
|
|
1634
1680
|
options = path
|
|
@@ -1640,7 +1686,7 @@ module ActionDispatch
|
|
|
1640
1686
|
when Symbol
|
|
1641
1687
|
options[:action] = to
|
|
1642
1688
|
when String
|
|
1643
|
-
if
|
|
1689
|
+
if to.include?("#")
|
|
1644
1690
|
options[:to] = to
|
|
1645
1691
|
else
|
|
1646
1692
|
options[:controller] = to
|
|
@@ -1665,17 +1711,17 @@ module ActionDispatch
|
|
|
1665
1711
|
|
|
1666
1712
|
# You can specify what Rails should route "/" to with the root method:
|
|
1667
1713
|
#
|
|
1668
|
-
#
|
|
1714
|
+
# root to: 'pages#main'
|
|
1669
1715
|
#
|
|
1670
|
-
# For options, see
|
|
1716
|
+
# For options, see `match`, as `root` uses it internally.
|
|
1671
1717
|
#
|
|
1672
1718
|
# You can also pass a string which will expand
|
|
1673
1719
|
#
|
|
1674
|
-
#
|
|
1720
|
+
# root 'pages#main'
|
|
1675
1721
|
#
|
|
1676
|
-
# You should put the root route at the top of
|
|
1677
|
-
#
|
|
1678
|
-
#
|
|
1722
|
+
# You should put the root route at the top of `config/routes.rb`, because this
|
|
1723
|
+
# means it will be matched first. As this is the most popular route of most
|
|
1724
|
+
# Rails applications, this is beneficial.
|
|
1679
1725
|
def root(path, options = {})
|
|
1680
1726
|
if path.is_a?(String)
|
|
1681
1727
|
options[:to] = path
|
|
@@ -1853,9 +1899,9 @@ module ActionDispatch
|
|
|
1853
1899
|
candidate = action_name.select(&:present?).join("_")
|
|
1854
1900
|
|
|
1855
1901
|
unless candidate.empty?
|
|
1856
|
-
# If a name was not explicitly given, we check if it is valid
|
|
1857
|
-
#
|
|
1858
|
-
#
|
|
1902
|
+
# If a name was not explicitly given, we check if it is valid and return nil in
|
|
1903
|
+
# case it isn't. Otherwise, we pass the invalid name forward so the underlying
|
|
1904
|
+
# router engine treats it and raises an exception.
|
|
1859
1905
|
if as.nil?
|
|
1860
1906
|
candidate unless !candidate.match?(/\A[_a-z]/i) || has_named_route?(candidate)
|
|
1861
1907
|
else
|
|
@@ -1991,83 +2037,81 @@ module ActionDispatch
|
|
|
1991
2037
|
end
|
|
1992
2038
|
end
|
|
1993
2039
|
|
|
1994
|
-
# Routing Concerns allow you to declare common routes that can be reused
|
|
1995
|
-
#
|
|
2040
|
+
# Routing Concerns allow you to declare common routes that can be reused inside
|
|
2041
|
+
# others resources and routes.
|
|
1996
2042
|
#
|
|
1997
|
-
#
|
|
1998
|
-
#
|
|
1999
|
-
#
|
|
2043
|
+
# concern :commentable do
|
|
2044
|
+
# resources :comments
|
|
2045
|
+
# end
|
|
2000
2046
|
#
|
|
2001
|
-
#
|
|
2002
|
-
#
|
|
2003
|
-
#
|
|
2047
|
+
# concern :image_attachable do
|
|
2048
|
+
# resources :images, only: :index
|
|
2049
|
+
# end
|
|
2004
2050
|
#
|
|
2005
2051
|
# These concerns are used in Resources routing:
|
|
2006
2052
|
#
|
|
2007
|
-
#
|
|
2053
|
+
# resources :messages, concerns: [:commentable, :image_attachable]
|
|
2008
2054
|
#
|
|
2009
2055
|
# or in a scope or namespace:
|
|
2010
2056
|
#
|
|
2011
|
-
#
|
|
2012
|
-
#
|
|
2013
|
-
#
|
|
2057
|
+
# namespace :posts do
|
|
2058
|
+
# concerns :commentable
|
|
2059
|
+
# end
|
|
2014
2060
|
module Concerns
|
|
2015
2061
|
# Define a routing concern using a name.
|
|
2016
2062
|
#
|
|
2017
|
-
# Concerns may be defined inline, using a block, or handled by
|
|
2018
|
-
#
|
|
2063
|
+
# Concerns may be defined inline, using a block, or handled by another object,
|
|
2064
|
+
# by passing that object as the second parameter.
|
|
2019
2065
|
#
|
|
2020
|
-
# The concern object, if supplied, should respond to
|
|
2021
|
-
#
|
|
2066
|
+
# The concern object, if supplied, should respond to `call`, which will receive
|
|
2067
|
+
# two parameters:
|
|
2022
2068
|
#
|
|
2023
|
-
#
|
|
2024
|
-
#
|
|
2069
|
+
# * The current mapper
|
|
2070
|
+
# * A hash of options which the concern object may use
|
|
2025
2071
|
#
|
|
2026
|
-
# Options may also be used by concerns defined in a block by accepting
|
|
2027
|
-
#
|
|
2028
|
-
#
|
|
2029
|
-
#
|
|
2072
|
+
# Options may also be used by concerns defined in a block by accepting a block
|
|
2073
|
+
# parameter. So, using a block, you might do something as simple as limit the
|
|
2074
|
+
# actions available on certain resources, passing standard resource options
|
|
2075
|
+
# through the concern:
|
|
2030
2076
|
#
|
|
2031
|
-
#
|
|
2032
|
-
#
|
|
2033
|
-
#
|
|
2077
|
+
# concern :commentable do |options|
|
|
2078
|
+
# resources :comments, options
|
|
2079
|
+
# end
|
|
2034
2080
|
#
|
|
2035
|
-
#
|
|
2036
|
-
#
|
|
2037
|
-
#
|
|
2038
|
-
#
|
|
2039
|
-
#
|
|
2081
|
+
# resources :posts, concerns: :commentable
|
|
2082
|
+
# resources :archived_posts do
|
|
2083
|
+
# # Don't allow comments on archived posts
|
|
2084
|
+
# concerns :commentable, only: [:index, :show]
|
|
2085
|
+
# end
|
|
2040
2086
|
#
|
|
2041
|
-
# Or, using a callable object, you might implement something more
|
|
2042
|
-
#
|
|
2043
|
-
# routes file.
|
|
2087
|
+
# Or, using a callable object, you might implement something more specific to
|
|
2088
|
+
# your application, which would be out of place in your routes file.
|
|
2044
2089
|
#
|
|
2045
|
-
#
|
|
2046
|
-
#
|
|
2047
|
-
#
|
|
2048
|
-
#
|
|
2049
|
-
#
|
|
2090
|
+
# # purchasable.rb
|
|
2091
|
+
# class Purchasable
|
|
2092
|
+
# def initialize(defaults = {})
|
|
2093
|
+
# @defaults = defaults
|
|
2094
|
+
# end
|
|
2050
2095
|
#
|
|
2051
|
-
#
|
|
2052
|
-
#
|
|
2053
|
-
#
|
|
2054
|
-
#
|
|
2055
|
-
#
|
|
2096
|
+
# def call(mapper, options = {})
|
|
2097
|
+
# options = @defaults.merge(options)
|
|
2098
|
+
# mapper.resources :purchases
|
|
2099
|
+
# mapper.resources :receipts
|
|
2100
|
+
# mapper.resources :returns if options[:returnable]
|
|
2101
|
+
# end
|
|
2056
2102
|
# end
|
|
2057
|
-
# end
|
|
2058
2103
|
#
|
|
2059
|
-
#
|
|
2060
|
-
#
|
|
2104
|
+
# # routes.rb
|
|
2105
|
+
# concern :purchasable, Purchasable.new(returnable: true)
|
|
2061
2106
|
#
|
|
2062
|
-
#
|
|
2063
|
-
#
|
|
2064
|
-
#
|
|
2065
|
-
#
|
|
2066
|
-
#
|
|
2107
|
+
# resources :toys, concerns: :purchasable
|
|
2108
|
+
# resources :electronics, concerns: :purchasable
|
|
2109
|
+
# resources :pets do
|
|
2110
|
+
# concerns :purchasable, returnable: false
|
|
2111
|
+
# end
|
|
2067
2112
|
#
|
|
2068
|
-
# Any routing helpers can be used inside a concern. If using a
|
|
2069
|
-
#
|
|
2070
|
-
# <tt>call</tt>.
|
|
2113
|
+
# Any routing helpers can be used inside a concern. If using a callable, they're
|
|
2114
|
+
# accessible from the Mapper that's passed to `call`.
|
|
2071
2115
|
def concern(name, callable = nil, &block)
|
|
2072
2116
|
callable ||= lambda { |mapper, options| mapper.instance_exec(options, &block) }
|
|
2073
2117
|
@concerns[name] = callable
|
|
@@ -2075,15 +2119,15 @@ module ActionDispatch
|
|
|
2075
2119
|
|
|
2076
2120
|
# Use the named concerns
|
|
2077
2121
|
#
|
|
2078
|
-
#
|
|
2079
|
-
#
|
|
2080
|
-
#
|
|
2122
|
+
# resources :posts do
|
|
2123
|
+
# concerns :commentable
|
|
2124
|
+
# end
|
|
2081
2125
|
#
|
|
2082
2126
|
# Concerns also work in any routes helper that you want to use:
|
|
2083
2127
|
#
|
|
2084
|
-
#
|
|
2085
|
-
#
|
|
2086
|
-
#
|
|
2128
|
+
# namespace :posts do
|
|
2129
|
+
# concerns :commentable
|
|
2130
|
+
# end
|
|
2087
2131
|
def concerns(*args)
|
|
2088
2132
|
options = args.extract_options!
|
|
2089
2133
|
args.flatten.each do |name|
|
|
@@ -2097,53 +2141,55 @@ module ActionDispatch
|
|
|
2097
2141
|
end
|
|
2098
2142
|
|
|
2099
2143
|
module CustomUrls
|
|
2100
|
-
# Define custom URL helpers that will be added to the application's
|
|
2101
|
-
#
|
|
2102
|
-
#
|
|
2144
|
+
# Define custom URL helpers that will be added to the application's routes. This
|
|
2145
|
+
# allows you to override and/or replace the default behavior of routing helpers,
|
|
2146
|
+
# e.g:
|
|
2103
2147
|
#
|
|
2104
|
-
#
|
|
2105
|
-
#
|
|
2106
|
-
#
|
|
2148
|
+
# direct :homepage do
|
|
2149
|
+
# "https://rubyonrails.org"
|
|
2150
|
+
# end
|
|
2107
2151
|
#
|
|
2108
|
-
#
|
|
2109
|
-
#
|
|
2110
|
-
#
|
|
2152
|
+
# direct :commentable do |model|
|
|
2153
|
+
# [ model, anchor: model.dom_id ]
|
|
2154
|
+
# end
|
|
2111
2155
|
#
|
|
2112
|
-
#
|
|
2113
|
-
#
|
|
2114
|
-
#
|
|
2156
|
+
# direct :main do
|
|
2157
|
+
# { controller: "pages", action: "index", subdomain: "www" }
|
|
2158
|
+
# end
|
|
2115
2159
|
#
|
|
2116
|
-
# The return value from the block passed to
|
|
2117
|
-
# arguments for
|
|
2118
|
-
#
|
|
2160
|
+
# The return value from the block passed to `direct` must be a valid set of
|
|
2161
|
+
# arguments for `url_for` which will actually build the URL string. This can be
|
|
2162
|
+
# one of the following:
|
|
2119
2163
|
#
|
|
2120
|
-
# *
|
|
2121
|
-
# *
|
|
2122
|
-
# *
|
|
2123
|
-
# *
|
|
2124
|
-
# *
|
|
2164
|
+
# * A string, which is treated as a generated URL
|
|
2165
|
+
# * A hash, e.g. `{ controller: "pages", action: "index" }`
|
|
2166
|
+
# * An array, which is passed to `polymorphic_url`
|
|
2167
|
+
# * An Active Model instance
|
|
2168
|
+
# * An Active Model class
|
|
2125
2169
|
#
|
|
2126
|
-
# NOTE: Other URL helpers can be called in the block but be careful not to invoke
|
|
2127
|
-
# your custom URL helper again otherwise it will result in a stack overflow error.
|
|
2128
2170
|
#
|
|
2129
|
-
#
|
|
2130
|
-
# your URL helper
|
|
2171
|
+
# NOTE: Other URL helpers can be called in the block but be careful not to
|
|
2172
|
+
# invoke your custom URL helper again otherwise it will result in a stack
|
|
2173
|
+
# overflow error.
|
|
2131
2174
|
#
|
|
2132
|
-
#
|
|
2133
|
-
#
|
|
2134
|
-
# end
|
|
2175
|
+
# You can also specify default options that will be passed through to your URL
|
|
2176
|
+
# helper definition, e.g:
|
|
2135
2177
|
#
|
|
2136
|
-
#
|
|
2137
|
-
#
|
|
2138
|
-
#
|
|
2178
|
+
# direct :browse, page: 1, size: 10 do |options|
|
|
2179
|
+
# [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
|
|
2180
|
+
# end
|
|
2181
|
+
#
|
|
2182
|
+
# In this instance the `params` object comes from the context in which the block
|
|
2183
|
+
# is executed, e.g. generating a URL inside a controller action or a view. If
|
|
2184
|
+
# the block is executed where there isn't a `params` object such as this:
|
|
2139
2185
|
#
|
|
2140
|
-
#
|
|
2186
|
+
# Rails.application.routes.url_helpers.browse_path
|
|
2141
2187
|
#
|
|
2142
|
-
# then it will raise a
|
|
2188
|
+
# then it will raise a `NameError`. Because of this you need to be aware of the
|
|
2143
2189
|
# context in which you will use your custom URL helper when defining it.
|
|
2144
2190
|
#
|
|
2145
|
-
# NOTE: The
|
|
2146
|
-
#
|
|
2191
|
+
# NOTE: The `direct` method can't be used inside of a scope block such as
|
|
2192
|
+
# `namespace` or `scope` and will raise an error if it detects that it is.
|
|
2147
2193
|
def direct(name, options = {}, &block)
|
|
2148
2194
|
unless @scope.root?
|
|
2149
2195
|
raise RuntimeError, "The direct method can't be used inside a routes scope block"
|
|
@@ -2152,50 +2198,50 @@ module ActionDispatch
|
|
|
2152
2198
|
@set.add_url_helper(name, options, &block)
|
|
2153
2199
|
end
|
|
2154
2200
|
|
|
2155
|
-
# Define custom polymorphic mappings of models to URLs. This alters the
|
|
2156
|
-
#
|
|
2157
|
-
#
|
|
2201
|
+
# Define custom polymorphic mappings of models to URLs. This alters the behavior
|
|
2202
|
+
# of `polymorphic_url` and consequently the behavior of `link_to` and `form_for`
|
|
2203
|
+
# when passed a model instance, e.g:
|
|
2158
2204
|
#
|
|
2159
|
-
#
|
|
2205
|
+
# resource :basket
|
|
2160
2206
|
#
|
|
2161
|
-
#
|
|
2162
|
-
#
|
|
2163
|
-
#
|
|
2207
|
+
# resolve "Basket" do
|
|
2208
|
+
# [:basket]
|
|
2209
|
+
# end
|
|
2164
2210
|
#
|
|
2165
|
-
# This will now generate "/basket" when a
|
|
2166
|
-
#
|
|
2211
|
+
# This will now generate "/basket" when a `Basket` instance is passed to
|
|
2212
|
+
# `link_to` or `form_for` instead of the standard "/baskets/:id".
|
|
2167
2213
|
#
|
|
2168
|
-
# NOTE: This custom behavior only applies to simple polymorphic URLs where
|
|
2169
|
-
#
|
|
2214
|
+
# NOTE: This custom behavior only applies to simple polymorphic URLs where a
|
|
2215
|
+
# single model instance is passed and not more complicated forms, e.g:
|
|
2170
2216
|
#
|
|
2171
|
-
#
|
|
2172
|
-
#
|
|
2173
|
-
#
|
|
2174
|
-
#
|
|
2175
|
-
#
|
|
2217
|
+
# # config/routes.rb
|
|
2218
|
+
# resource :profile
|
|
2219
|
+
# namespace :admin do
|
|
2220
|
+
# resources :users
|
|
2221
|
+
# end
|
|
2176
2222
|
#
|
|
2177
|
-
#
|
|
2223
|
+
# resolve("User") { [:profile] }
|
|
2178
2224
|
#
|
|
2179
|
-
#
|
|
2180
|
-
#
|
|
2181
|
-
#
|
|
2225
|
+
# # app/views/application/_menu.html.erb
|
|
2226
|
+
# link_to "Profile", @current_user
|
|
2227
|
+
# link_to "Profile", [:admin, @current_user]
|
|
2182
2228
|
#
|
|
2183
|
-
# The first
|
|
2184
|
-
#
|
|
2229
|
+
# The first `link_to` will generate "/profile" but the second will generate the
|
|
2230
|
+
# standard polymorphic URL of "/admin/users/1".
|
|
2185
2231
|
#
|
|
2186
|
-
# You can pass options to a polymorphic mapping - the arity for the block
|
|
2187
|
-
#
|
|
2232
|
+
# You can pass options to a polymorphic mapping - the arity for the block needs
|
|
2233
|
+
# to be two as the instance is passed as the first argument, e.g:
|
|
2188
2234
|
#
|
|
2189
|
-
#
|
|
2190
|
-
#
|
|
2191
|
-
#
|
|
2235
|
+
# resolve "Basket", anchor: "items" do |basket, options|
|
|
2236
|
+
# [:basket, options]
|
|
2237
|
+
# end
|
|
2192
2238
|
#
|
|
2193
|
-
# This generates the URL "/basket#items" because when the last item in an
|
|
2194
|
-
#
|
|
2195
|
-
#
|
|
2239
|
+
# This generates the URL "/basket#items" because when the last item in an array
|
|
2240
|
+
# passed to `polymorphic_url` is a hash then it's treated as options to the URL
|
|
2241
|
+
# helper that gets called.
|
|
2196
2242
|
#
|
|
2197
|
-
# NOTE: The
|
|
2198
|
-
#
|
|
2243
|
+
# NOTE: The `resolve` method can't be used inside of a scope block such as
|
|
2244
|
+
# `namespace` or `scope` and will raise an error if it detects that it is.
|
|
2199
2245
|
def resolve(*args, &block)
|
|
2200
2246
|
unless @scope.root?
|
|
2201
2247
|
raise RuntimeError, "The resolve method can't be used inside a routes scope block"
|