actionpack 7.1.5.1 → 7.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -642
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +102 -98
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +70 -85
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +12 -13
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +74 -72
- data/lib/action_controller/base.rb +155 -117
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +119 -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 +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +64 -55
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +214 -203
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +113 -107
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +108 -82
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -75
- data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +483 -478
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +58 -57
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +42 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +146 -126
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +2 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +48 -59
- data/lib/action_dispatch/http/filter_parameters.rb +13 -14
- data/lib/action_dispatch/http/filter_redirect.rb +15 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +26 -36
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +75 -95
- data/lib/action_dispatch/http/response.rb +61 -61
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +13 -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 +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- 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 +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
- data/lib/action_dispatch/middleware/executor.rb +2 -0
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -3
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +6 -4
- data/lib/action_dispatch/routing/mapper.rb +623 -625
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +60 -46
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +4 -2
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +8 -6
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +223 -222
- data/lib/action_dispatch/testing/request_encoder.rb +2 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +12 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +22 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +33 -16
@@ -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"
|
@@ -31,10 +33,10 @@ module ActionDispatch
|
|
31
33
|
CALL = ->(app, req) { app.call req.env }
|
32
34
|
|
33
35
|
def initialize(app, constraints, strategy)
|
34
|
-
# Unwrap Constraints objects. I don't actually think it's possible
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
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.
|
38
40
|
if app.is_a?(self.class)
|
39
41
|
constraints += app.constraints
|
40
42
|
app = app.app
|
@@ -219,7 +221,7 @@ module ActionDispatch
|
|
219
221
|
# Add a default constraint for :controller path segments that matches namespaced
|
220
222
|
# controllers with default routes like :controller/:action/:id(.:format), e.g:
|
221
223
|
# GET /admin/products/show/1
|
222
|
-
#
|
224
|
+
# # > { controller: 'admin/products', action: 'show', id: '1' }
|
223
225
|
options[:controller] ||= /.+?/
|
224
226
|
end
|
225
227
|
|
@@ -406,22 +408,20 @@ module ActionDispatch
|
|
406
408
|
end
|
407
409
|
end
|
408
410
|
|
409
|
-
# Invokes Journey::Router::Utils.normalize_path, then ensures that
|
410
|
-
#
|
411
|
-
#
|
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.
|
412
414
|
def self.normalize_path(path)
|
413
415
|
path = Journey::Router::Utils.normalize_path(path)
|
414
416
|
|
415
417
|
# the path for a root URL at this point can be something like
|
416
418
|
# "/(/:locale)(/:platform)/(:browser)", and we would want
|
417
|
-
# "/(:locale)(/:platform)(/:browser)"
|
418
|
-
|
419
|
-
# reverse "/(", "/((" etc to "(/", "((/" etc
|
419
|
+
# "/(:locale)(/:platform)(/:browser)" reverse "/(", "/((" etc to "(/", "((/" etc
|
420
420
|
path.gsub!(%r{/(\(+)/?}, '\1/')
|
421
|
-
# if a path is all optional segments, change the leading "(/" back to
|
422
|
-
#
|
423
|
-
#
|
424
|
-
#
|
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)"
|
425
425
|
path.sub!(%r{^(\(+)/}, '/\1') if %r{^(\(+[^)]+\))(\(+/:[^)]+\))*$}.match?(path)
|
426
426
|
path
|
427
427
|
end
|
@@ -433,206 +433,202 @@ module ActionDispatch
|
|
433
433
|
module Base
|
434
434
|
# Matches a URL pattern to one or more routes.
|
435
435
|
#
|
436
|
-
# You should not use the
|
437
|
-
#
|
436
|
+
# You should not use the `match` method in your router without specifying an
|
437
|
+
# HTTP method.
|
438
438
|
#
|
439
439
|
# If you want to expose your action to both GET and POST, use:
|
440
440
|
#
|
441
|
-
#
|
442
|
-
#
|
441
|
+
# # sets :controller, :action, and :id in params
|
442
|
+
# match ':controller/:action/:id', via: [:get, :post]
|
443
443
|
#
|
444
|
-
# Note that
|
445
|
-
#
|
444
|
+
# Note that `:controller`, `:action`, and `:id` are interpreted as URL query
|
445
|
+
# parameters and thus available through `params` in an action.
|
446
446
|
#
|
447
|
-
# 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:
|
448
448
|
#
|
449
449
|
# Instead of:
|
450
450
|
#
|
451
|
-
#
|
451
|
+
# match ":controller/:action/:id"
|
452
452
|
#
|
453
453
|
# Do:
|
454
454
|
#
|
455
|
-
#
|
455
|
+
# get ":controller/:action/:id"
|
456
456
|
#
|
457
|
-
# Two of these symbols are special,
|
458
|
-
#
|
459
|
-
#
|
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:
|
460
460
|
#
|
461
|
-
#
|
461
|
+
# get 'songs/*category/:title', to: 'songs#show'
|
462
462
|
#
|
463
|
-
#
|
464
|
-
#
|
465
|
-
#
|
463
|
+
# # 'songs/rock/classic/stairway-to-heaven' sets
|
464
|
+
# # params[:category] = 'rock/classic'
|
465
|
+
# # params[:title] = 'stairway-to-heaven'
|
466
466
|
#
|
467
|
-
# To match a wildcard parameter, it must have a name assigned to it.
|
468
|
-
#
|
469
|
-
# 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.
|
470
469
|
#
|
471
|
-
# When a pattern points to an internal route, the route's
|
472
|
-
#
|
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:
|
473
472
|
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
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
|
477
476
|
#
|
478
|
-
# A pattern can also point to a
|
479
|
-
#
|
477
|
+
# A pattern can also point to a `Rack` endpoint i.e. anything that responds to
|
478
|
+
# `call`:
|
480
479
|
#
|
481
|
-
#
|
482
|
-
#
|
483
|
-
#
|
484
|
-
#
|
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
|
485
484
|
#
|
486
485
|
# Because requesting various HTTP verbs with a single action has security
|
487
|
-
# implications, you must either specify the actions in
|
488
|
-
#
|
489
|
-
# 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`
|
490
488
|
#
|
491
|
-
#
|
489
|
+
# ### Options
|
492
490
|
#
|
493
491
|
# Any options not seen here are passed on as params with the URL.
|
494
492
|
#
|
495
|
-
#
|
496
|
-
# The route's controller.
|
493
|
+
# :controller
|
494
|
+
# : The route's controller.
|
497
495
|
#
|
498
|
-
#
|
499
|
-
# The route's action.
|
496
|
+
# :action
|
497
|
+
# : The route's action.
|
500
498
|
#
|
501
|
-
#
|
502
|
-
# Overrides the default resource identifier
|
503
|
-
#
|
504
|
-
#
|
505
|
-
# <tt>params[<:param>]</tt>.
|
506
|
-
# 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:
|
507
503
|
#
|
508
|
-
#
|
504
|
+
# resources :users, param: :name
|
509
505
|
#
|
510
|
-
#
|
506
|
+
# The `users` resource here will have the following routes generated for it:
|
511
507
|
#
|
512
|
-
#
|
513
|
-
#
|
514
|
-
#
|
515
|
-
#
|
516
|
-
#
|
517
|
-
#
|
518
|
-
#
|
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)
|
519
515
|
#
|
520
|
-
#
|
521
|
-
#
|
516
|
+
# You can override `ActiveRecord::Base#to_param` of a related model to
|
517
|
+
# construct a URL:
|
522
518
|
#
|
523
|
-
#
|
524
|
-
#
|
525
|
-
#
|
526
|
-
#
|
527
|
-
#
|
519
|
+
# class User < ActiveRecord::Base
|
520
|
+
# def to_param
|
521
|
+
# name
|
522
|
+
# end
|
523
|
+
# end
|
528
524
|
#
|
529
|
-
#
|
530
|
-
#
|
525
|
+
# user = User.find_by(name: 'Phusion')
|
526
|
+
# user_path(user) # => "/users/Phusion"
|
531
527
|
#
|
532
|
-
#
|
533
|
-
# The path prefix for the routes.
|
528
|
+
# :path
|
529
|
+
# : The path prefix for the routes.
|
534
530
|
#
|
535
|
-
#
|
536
|
-
# The namespace for :controller.
|
531
|
+
# :module
|
532
|
+
# : The namespace for :controller.
|
537
533
|
#
|
538
|
-
#
|
539
|
-
#
|
534
|
+
# match 'path', to: 'c#a', module: 'sekret', controller: 'posts', via: :get
|
535
|
+
# # => Sekret::PostsController
|
540
536
|
#
|
541
|
-
#
|
537
|
+
# See `Scoping#namespace` for its scope equivalent.
|
542
538
|
#
|
543
|
-
#
|
544
|
-
# The name used to generate routing helpers.
|
539
|
+
# :as
|
540
|
+
# : The name used to generate routing helpers.
|
545
541
|
#
|
546
|
-
#
|
547
|
-
# Allowed HTTP verb(s) for route.
|
542
|
+
# :via
|
543
|
+
# : Allowed HTTP verb(s) for route.
|
548
544
|
#
|
549
|
-
#
|
550
|
-
#
|
551
|
-
#
|
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
|
552
548
|
#
|
553
|
-
#
|
554
|
-
# Points to a
|
555
|
-
#
|
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.
|
556
552
|
#
|
557
|
-
#
|
558
|
-
#
|
559
|
-
#
|
553
|
+
# match 'path', to: 'controller#action', via: :get
|
554
|
+
# match 'path', to: -> (env) { [200, {}, ["Success!"]] }, via: :get
|
555
|
+
# match 'path', to: RackApp, via: :get
|
560
556
|
#
|
561
|
-
#
|
562
|
-
# Shorthand for wrapping routes in a specific RESTful context. Valid
|
563
|
-
#
|
564
|
-
#
|
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:
|
565
561
|
#
|
566
|
-
#
|
567
|
-
#
|
568
|
-
#
|
562
|
+
# resource :bar do
|
563
|
+
# match 'foo', to: 'c#a', on: :member, via: [:get, :post]
|
564
|
+
# end
|
569
565
|
#
|
570
|
-
#
|
566
|
+
# Is equivalent to:
|
571
567
|
#
|
572
|
-
#
|
573
|
-
#
|
574
|
-
#
|
575
|
-
#
|
576
|
-
#
|
568
|
+
# resource :bar do
|
569
|
+
# member do
|
570
|
+
# match 'foo', to: 'c#a', via: [:get, :post]
|
571
|
+
# end
|
572
|
+
# end
|
577
573
|
#
|
578
|
-
#
|
579
|
-
# Constrains parameters with a hash of regular expressions
|
580
|
-
#
|
581
|
-
#
|
582
|
-
#
|
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.).
|
583
579
|
#
|
584
|
-
#
|
580
|
+
# match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: :get
|
585
581
|
#
|
586
|
-
#
|
582
|
+
# match 'json_only', constraints: { format: 'json' }, via: :get
|
587
583
|
#
|
588
|
-
#
|
589
|
-
#
|
590
|
-
#
|
591
|
-
#
|
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
|
588
|
+
#
|
589
|
+
# See `Scoping#constraints` for more examples with its scope equivalent.
|
592
590
|
#
|
593
|
-
#
|
594
|
-
#
|
591
|
+
# :defaults
|
592
|
+
# : Sets defaults for parameters
|
595
593
|
#
|
596
|
-
# [:
|
597
|
-
#
|
594
|
+
# # Sets params[:format] to 'jpg' by default
|
595
|
+
# match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: :get
|
598
596
|
#
|
599
|
-
# #
|
600
|
-
# match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: :get
|
597
|
+
# See `Scoping#defaults` for its scope equivalent.
|
601
598
|
#
|
602
|
-
#
|
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.
|
603
602
|
#
|
604
|
-
#
|
605
|
-
#
|
606
|
-
# false, the pattern matches any request prefixed with the given path.
|
603
|
+
# # Matches any request starting with 'path'
|
604
|
+
# match 'path', to: 'c#a', anchor: false, via: :get
|
607
605
|
#
|
608
|
-
#
|
609
|
-
#
|
606
|
+
# :format
|
607
|
+
# : Allows you to specify the default value for optional `format` segment or
|
608
|
+
# disable it by supplying `false`.
|
610
609
|
#
|
611
|
-
# [:format]
|
612
|
-
# Allows you to specify the default value for optional +format+
|
613
|
-
# segment or disable it by supplying +false+.
|
614
610
|
def match(path, options = nil)
|
615
611
|
end
|
616
612
|
|
617
613
|
# Mount a Rack-based application to be used within the application.
|
618
614
|
#
|
619
|
-
#
|
615
|
+
# mount SomeRackApp, at: "some_route"
|
620
616
|
#
|
621
617
|
# Alternatively:
|
622
618
|
#
|
623
|
-
#
|
619
|
+
# mount(SomeRackApp => "some_route")
|
624
620
|
#
|
625
|
-
# For options, see
|
621
|
+
# For options, see `match`, as `mount` uses it internally.
|
626
622
|
#
|
627
|
-
# All mounted applications come with routing helpers to access them.
|
628
|
-
#
|
629
|
-
#
|
630
|
-
#
|
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:
|
631
627
|
#
|
632
|
-
#
|
628
|
+
# mount(SomeRackApp => "some_route", as: "exciting")
|
633
629
|
#
|
634
|
-
# This will generate the
|
635
|
-
#
|
630
|
+
# This will generate the `exciting_path` and `exciting_url` helpers which can be
|
631
|
+
# used to navigate to this mounted app.
|
636
632
|
def mount(app, options = nil)
|
637
633
|
if options
|
638
634
|
path = options.delete(:at)
|
@@ -706,7 +702,8 @@ module ActionDispatch
|
|
706
702
|
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
|
707
703
|
end
|
708
704
|
|
709
|
-
# 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.
|
710
707
|
_route.segment_keys.each { |k| options.delete(k) }
|
711
708
|
_url_helpers.public_send("#{name}_path", prefix_options)
|
712
709
|
end
|
@@ -717,7 +714,7 @@ module ActionDispatch
|
|
717
714
|
def optimize_routes_generation?; false; end
|
718
715
|
|
719
716
|
define_method :find_script_name do |options|
|
720
|
-
if options.key?
|
717
|
+
if options.key? :script_name
|
721
718
|
super(options)
|
722
719
|
else
|
723
720
|
script_namer.call(options)
|
@@ -728,50 +725,50 @@ module ActionDispatch
|
|
728
725
|
end
|
729
726
|
|
730
727
|
module HttpHelpers
|
731
|
-
# Define a route that only recognizes HTTP GET.
|
732
|
-
#
|
728
|
+
# Define a route that only recognizes HTTP GET. For supported arguments, see
|
729
|
+
# [match](rdoc-ref:Base#match)
|
733
730
|
#
|
734
|
-
#
|
731
|
+
# get 'bacon', to: 'food#bacon'
|
735
732
|
def get(*args, &block)
|
736
733
|
map_method(:get, args, &block)
|
737
734
|
end
|
738
735
|
|
739
|
-
# Define a route that only recognizes HTTP POST.
|
740
|
-
#
|
736
|
+
# Define a route that only recognizes HTTP POST. For supported arguments, see
|
737
|
+
# [match](rdoc-ref:Base#match)
|
741
738
|
#
|
742
|
-
#
|
739
|
+
# post 'bacon', to: 'food#bacon'
|
743
740
|
def post(*args, &block)
|
744
741
|
map_method(:post, args, &block)
|
745
742
|
end
|
746
743
|
|
747
|
-
# Define a route that only recognizes HTTP PATCH.
|
748
|
-
#
|
744
|
+
# Define a route that only recognizes HTTP PATCH. For supported arguments, see
|
745
|
+
# [match](rdoc-ref:Base#match)
|
749
746
|
#
|
750
|
-
#
|
747
|
+
# patch 'bacon', to: 'food#bacon'
|
751
748
|
def patch(*args, &block)
|
752
749
|
map_method(:patch, args, &block)
|
753
750
|
end
|
754
751
|
|
755
|
-
# Define a route that only recognizes HTTP PUT.
|
756
|
-
#
|
752
|
+
# Define a route that only recognizes HTTP PUT. For supported arguments, see
|
753
|
+
# [match](rdoc-ref:Base#match)
|
757
754
|
#
|
758
|
-
#
|
755
|
+
# put 'bacon', to: 'food#bacon'
|
759
756
|
def put(*args, &block)
|
760
757
|
map_method(:put, args, &block)
|
761
758
|
end
|
762
759
|
|
763
|
-
# Define a route that only recognizes HTTP DELETE.
|
764
|
-
#
|
760
|
+
# Define a route that only recognizes HTTP DELETE. For supported arguments, see
|
761
|
+
# [match](rdoc-ref:Base#match)
|
765
762
|
#
|
766
|
-
#
|
763
|
+
# delete 'broccoli', to: 'food#broccoli'
|
767
764
|
def delete(*args, &block)
|
768
765
|
map_method(:delete, args, &block)
|
769
766
|
end
|
770
767
|
|
771
|
-
# Define a route that only recognizes HTTP OPTIONS.
|
772
|
-
#
|
768
|
+
# Define a route that only recognizes HTTP OPTIONS. For supported arguments, see
|
769
|
+
# [match](rdoc-ref:Base#match)
|
773
770
|
#
|
774
|
-
#
|
771
|
+
# options 'carrots', to: 'food#carrots'
|
775
772
|
def options(*args, &block)
|
776
773
|
map_method(:options, args, &block)
|
777
774
|
end
|
@@ -785,91 +782,90 @@ module ActionDispatch
|
|
785
782
|
end
|
786
783
|
end
|
787
784
|
|
788
|
-
# You may wish to organize groups of controllers under a namespace.
|
789
|
-
#
|
790
|
-
#
|
791
|
-
#
|
792
|
-
#
|
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:
|
793
790
|
#
|
794
|
-
#
|
795
|
-
#
|
796
|
-
#
|
791
|
+
# namespace "admin" do
|
792
|
+
# resources :posts, :comments
|
793
|
+
# end
|
797
794
|
#
|
798
795
|
# This will create a number of routes for each of the posts and comments
|
799
|
-
# controller. For
|
796
|
+
# controller. For `Admin::PostsController`, Rails will create:
|
800
797
|
#
|
801
|
-
#
|
802
|
-
#
|
803
|
-
#
|
804
|
-
#
|
805
|
-
#
|
806
|
-
#
|
807
|
-
#
|
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
|
808
805
|
#
|
809
806
|
# If you want to route /posts (without the prefix /admin) to
|
810
|
-
#
|
807
|
+
# `Admin::PostsController`, you could use
|
811
808
|
#
|
812
|
-
#
|
813
|
-
#
|
814
|
-
#
|
809
|
+
# scope module: "admin" do
|
810
|
+
# resources :posts
|
811
|
+
# end
|
815
812
|
#
|
816
813
|
# or, for a single case
|
817
814
|
#
|
818
|
-
#
|
815
|
+
# resources :posts, module: "admin"
|
819
816
|
#
|
820
|
-
# If you want to route /admin/posts to
|
821
|
-
#
|
817
|
+
# If you want to route /admin/posts to `PostsController` (without the `Admin::`
|
818
|
+
# module prefix), you could use
|
822
819
|
#
|
823
|
-
#
|
824
|
-
#
|
825
|
-
#
|
820
|
+
# scope "/admin" do
|
821
|
+
# resources :posts
|
822
|
+
# end
|
826
823
|
#
|
827
824
|
# or, for a single case
|
828
825
|
#
|
829
|
-
#
|
826
|
+
# resources :posts, path: "/admin/posts"
|
830
827
|
#
|
831
|
-
# In each of these cases, the named routes remain the same as if you did
|
832
|
-
#
|
833
|
-
# +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`:
|
834
830
|
#
|
835
|
-
#
|
836
|
-
#
|
837
|
-
#
|
838
|
-
#
|
839
|
-
#
|
840
|
-
#
|
841
|
-
#
|
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
|
842
838
|
module Scoping
|
843
839
|
# Scopes a set of routes to the given default options.
|
844
840
|
#
|
845
841
|
# Take the following route definition as an example:
|
846
842
|
#
|
847
|
-
#
|
848
|
-
#
|
849
|
-
#
|
843
|
+
# scope path: ":account_id", as: "account" do
|
844
|
+
# resources :projects
|
845
|
+
# end
|
850
846
|
#
|
851
|
-
# This generates helpers such as
|
852
|
-
# The difference here being that the routes generated are like
|
853
|
-
# 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.
|
854
850
|
#
|
855
|
-
#
|
851
|
+
# ### Options
|
856
852
|
#
|
857
|
-
# Takes same options as
|
853
|
+
# Takes same options as `Base#match` and `Resources#resources`.
|
858
854
|
#
|
859
|
-
#
|
860
|
-
#
|
861
|
-
#
|
862
|
-
#
|
855
|
+
# # route /posts (without the prefix /admin) to +Admin::PostsController+
|
856
|
+
# scope module: "admin" do
|
857
|
+
# resources :posts
|
858
|
+
# end
|
863
859
|
#
|
864
|
-
#
|
865
|
-
#
|
866
|
-
#
|
867
|
-
#
|
860
|
+
# # prefix the posts resource's requests with '/admin'
|
861
|
+
# scope path: "/admin" do
|
862
|
+
# resources :posts
|
863
|
+
# end
|
868
864
|
#
|
869
|
-
#
|
870
|
-
#
|
871
|
-
#
|
872
|
-
#
|
865
|
+
# # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
|
866
|
+
# scope as: "sekret" do
|
867
|
+
# resources :posts
|
868
|
+
# end
|
873
869
|
def scope(*args)
|
874
870
|
options = args.extract_options!.dup
|
875
871
|
scope = {}
|
@@ -926,9 +922,9 @@ module ActionDispatch
|
|
926
922
|
|
927
923
|
# Scopes routes to a specific controller
|
928
924
|
#
|
929
|
-
#
|
930
|
-
#
|
931
|
-
#
|
925
|
+
# controller "food" do
|
926
|
+
# match "bacon", action: :bacon, via: :get
|
927
|
+
# end
|
932
928
|
def controller(controller)
|
933
929
|
@scope = @scope.new(controller: controller)
|
934
930
|
yield
|
@@ -938,42 +934,42 @@ module ActionDispatch
|
|
938
934
|
|
939
935
|
# Scopes routes to a specific namespace. For example:
|
940
936
|
#
|
941
|
-
#
|
942
|
-
#
|
943
|
-
#
|
937
|
+
# namespace :admin do
|
938
|
+
# resources :posts
|
939
|
+
# end
|
944
940
|
#
|
945
941
|
# This generates the following routes:
|
946
942
|
#
|
947
|
-
#
|
948
|
-
#
|
949
|
-
#
|
950
|
-
#
|
951
|
-
#
|
952
|
-
#
|
953
|
-
#
|
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
|
954
950
|
#
|
955
|
-
#
|
951
|
+
# ### Options
|
956
952
|
#
|
957
|
-
# The
|
958
|
-
#
|
953
|
+
# The `:path`, `:as`, `:module`, `:shallow_path`, and `:shallow_prefix` options
|
954
|
+
# all default to the name of the namespace.
|
959
955
|
#
|
960
|
-
# For options, see
|
961
|
-
#
|
956
|
+
# For options, see `Base#match`. For `:shallow_path` option, see
|
957
|
+
# `Resources#resources`.
|
962
958
|
#
|
963
|
-
#
|
964
|
-
#
|
965
|
-
#
|
966
|
-
#
|
959
|
+
# # accessible through /sekret/posts rather than /admin/posts
|
960
|
+
# namespace :admin, path: "sekret" do
|
961
|
+
# resources :posts
|
962
|
+
# end
|
967
963
|
#
|
968
|
-
#
|
969
|
-
#
|
970
|
-
#
|
971
|
-
#
|
964
|
+
# # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
|
965
|
+
# namespace :admin, module: "sekret" do
|
966
|
+
# resources :posts
|
967
|
+
# end
|
972
968
|
#
|
973
|
-
#
|
974
|
-
#
|
975
|
-
#
|
976
|
-
#
|
969
|
+
# # generates +sekret_posts_path+ rather than +admin_posts_path+
|
970
|
+
# namespace :admin, as: "sekret" do
|
971
|
+
# resources :posts
|
972
|
+
# end
|
977
973
|
def namespace(path, options = {}, &block)
|
978
974
|
path = path.to_s
|
979
975
|
|
@@ -989,70 +985,74 @@ module ActionDispatch
|
|
989
985
|
end
|
990
986
|
end
|
991
987
|
|
992
|
-
#
|
993
|
-
# Allows you to constrain the nested routes based on a set of rules.
|
994
|
-
#
|
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:
|
995
992
|
#
|
996
|
-
#
|
997
|
-
#
|
998
|
-
#
|
993
|
+
# constraints(id: /\d+\.\d+/) do
|
994
|
+
# resources :posts
|
995
|
+
# end
|
999
996
|
#
|
1000
|
-
# Now routes such as
|
1001
|
-
# 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.
|
1002
999
|
#
|
1003
1000
|
# You may use this to also restrict other parameters:
|
1004
1001
|
#
|
1005
|
-
#
|
1006
|
-
#
|
1007
|
-
#
|
1002
|
+
# resources :posts do
|
1003
|
+
# constraints(post_id: /\d+\.\d+/) do
|
1004
|
+
# resources :comments
|
1005
|
+
# end
|
1008
1006
|
# end
|
1009
|
-
# end
|
1010
1007
|
#
|
1011
|
-
#
|
1008
|
+
# ### Restricting based on IP
|
1012
1009
|
#
|
1013
1010
|
# Routes can also be constrained to an IP or a certain range of IP addresses:
|
1014
1011
|
#
|
1015
|
-
#
|
1016
|
-
#
|
1017
|
-
#
|
1012
|
+
# constraints(ip: /192\.168\.\d+\.\d+/) do
|
1013
|
+
# resources :posts
|
1014
|
+
# end
|
1018
1015
|
#
|
1019
|
-
# Any user connecting from the 192.168.* range will be able to see this
|
1020
|
-
# 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.
|
1021
1019
|
#
|
1022
|
-
#
|
1020
|
+
# ### Dynamic request matching
|
1023
1021
|
#
|
1024
1022
|
# Requests to routes can be constrained based on specific criteria:
|
1025
1023
|
#
|
1026
|
-
#
|
1027
|
-
#
|
1028
|
-
#
|
1024
|
+
# constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
|
1025
|
+
# resources :iphones
|
1026
|
+
# end
|
1029
1027
|
#
|
1030
|
-
# You are able to move this logic out into a class if it is too complex for
|
1031
|
-
# This class must have a
|
1032
|
-
# 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.
|
1033
1032
|
#
|
1034
|
-
#
|
1035
|
-
#
|
1036
|
-
#
|
1037
|
-
#
|
1038
|
-
#
|
1033
|
+
# class Iphone
|
1034
|
+
# def self.matches?(request)
|
1035
|
+
# /iPhone/.match?(request.env["HTTP_USER_AGENT"])
|
1036
|
+
# end
|
1037
|
+
# end
|
1039
1038
|
#
|
1040
|
-
# An expected place for this code would be
|
1039
|
+
# An expected place for this code would be `lib/constraints`.
|
1041
1040
|
#
|
1042
1041
|
# This class is then used like this:
|
1043
1042
|
#
|
1044
|
-
#
|
1045
|
-
#
|
1046
|
-
#
|
1043
|
+
# constraints(Iphone) do
|
1044
|
+
# resources :iphones
|
1045
|
+
# end
|
1047
1046
|
def constraints(constraints = {}, &block)
|
1048
1047
|
scope(constraints: constraints, &block)
|
1049
1048
|
end
|
1050
1049
|
|
1051
1050
|
# Allows you to set default parameters for a route, such as this:
|
1052
|
-
#
|
1053
|
-
#
|
1054
|
-
#
|
1055
|
-
#
|
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'.
|
1056
1056
|
def defaults(defaults = {})
|
1057
1057
|
@scope = @scope.new(defaults: merge_defaults_scope(@scope[:defaults], defaults))
|
1058
1058
|
yield
|
@@ -1128,48 +1128,46 @@ module ActionDispatch
|
|
1128
1128
|
end
|
1129
1129
|
end
|
1130
1130
|
|
1131
|
-
# Resource routing allows you to quickly declare all of the common routes
|
1132
|
-
#
|
1133
|
-
#
|
1134
|
-
#
|
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:
|
1135
1135
|
#
|
1136
|
-
#
|
1136
|
+
# resources :photos
|
1137
1137
|
#
|
1138
|
-
# Sometimes, you have a resource that clients always look up without
|
1139
|
-
#
|
1140
|
-
#
|
1141
|
-
#
|
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.
|
1142
1142
|
#
|
1143
|
-
#
|
1143
|
+
# resource :profile
|
1144
1144
|
#
|
1145
|
-
# It's common to have resources that are logically children of other
|
1146
|
-
# resources:
|
1145
|
+
# It's common to have resources that are logically children of other resources:
|
1147
1146
|
#
|
1148
|
-
#
|
1149
|
-
#
|
1150
|
-
#
|
1147
|
+
# resources :magazines do
|
1148
|
+
# resources :ads
|
1149
|
+
# end
|
1151
1150
|
#
|
1152
1151
|
# You may wish to organize groups of controllers under a namespace. Most
|
1153
|
-
# commonly, you might group a number of administrative controllers under
|
1154
|
-
#
|
1155
|
-
#
|
1156
|
-
#
|
1157
|
-
#
|
1158
|
-
# namespace "admin" do
|
1159
|
-
# resources :posts, :comments
|
1160
|
-
# end
|
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:
|
1161
1156
|
#
|
1162
|
-
#
|
1163
|
-
#
|
1164
|
-
#
|
1157
|
+
# namespace "admin" do
|
1158
|
+
# resources :posts, :comments
|
1159
|
+
# end
|
1165
1160
|
#
|
1166
|
-
#
|
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:
|
1167
1164
|
#
|
1168
|
-
#
|
1165
|
+
# resources :articles, id: /[^\/]+/
|
1169
1166
|
#
|
1167
|
+
# This allows any character other than a slash as part of your `:id`.
|
1170
1168
|
module Resources
|
1171
|
-
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
|
1172
|
-
#
|
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.
|
1173
1171
|
VALID_ON_OPTIONS = [:new, :collection, :member]
|
1174
1172
|
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
1175
1173
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
@@ -1232,8 +1230,8 @@ module ActionDispatch
|
|
1232
1230
|
|
1233
1231
|
alias :member_name :singular
|
1234
1232
|
|
1235
|
-
# Checks for uncountable plurals, and appends "_index" if the plural
|
1236
|
-
#
|
1233
|
+
# Checks for uncountable plurals, and appends "_index" if the plural and
|
1234
|
+
# singular form are the same.
|
1237
1235
|
def collection_name
|
1238
1236
|
singular == plural ? "#{plural}_index" : plural
|
1239
1237
|
end
|
@@ -1306,37 +1304,35 @@ module ActionDispatch
|
|
1306
1304
|
@scope[:path_names].merge!(options)
|
1307
1305
|
end
|
1308
1306
|
|
1309
|
-
# Sometimes, you have a resource that clients always look up without
|
1310
|
-
#
|
1311
|
-
#
|
1312
|
-
#
|
1313
|
-
# 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:
|
1314
1311
|
#
|
1315
|
-
#
|
1312
|
+
# resource :profile
|
1316
1313
|
#
|
1317
|
-
# This creates six different routes in your application, all mapping to
|
1318
|
-
#
|
1319
|
-
# 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):
|
1320
1316
|
#
|
1321
|
-
#
|
1322
|
-
#
|
1323
|
-
#
|
1324
|
-
#
|
1325
|
-
#
|
1326
|
-
#
|
1317
|
+
# GET /profile/new
|
1318
|
+
# GET /profile
|
1319
|
+
# GET /profile/edit
|
1320
|
+
# PATCH/PUT /profile
|
1321
|
+
# DELETE /profile
|
1322
|
+
# POST /profile
|
1327
1323
|
#
|
1328
|
-
# If you want instances of a model to work with this resource via
|
1329
|
-
#
|
1330
|
-
#
|
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):
|
1331
1327
|
#
|
1332
|
-
#
|
1333
|
-
#
|
1328
|
+
# resource :profile
|
1329
|
+
# resolve('Profile') { [:profile] }
|
1334
1330
|
#
|
1335
|
-
#
|
1336
|
-
#
|
1331
|
+
# # Enables this to work with singular routes:
|
1332
|
+
# form_with(model: @profile) {}
|
1337
1333
|
#
|
1338
|
-
#
|
1339
|
-
# Takes same options as resources
|
1334
|
+
# ### Options
|
1335
|
+
# Takes same options as [resources](rdoc-ref:#resources)
|
1340
1336
|
def resource(*resources, &block)
|
1341
1337
|
options = resources.extract_options!.dup
|
1342
1338
|
|
@@ -1366,143 +1362,147 @@ module ActionDispatch
|
|
1366
1362
|
self
|
1367
1363
|
end
|
1368
1364
|
|
1369
|
-
# In
|
1370
|
-
# and
|
1371
|
-
#
|
1372
|
-
# 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
|
1373
1368
|
#
|
1374
|
-
#
|
1369
|
+
# resources :photos
|
1375
1370
|
#
|
1376
|
-
# creates seven different routes in your application, all mapping to
|
1377
|
-
#
|
1371
|
+
# creates seven different routes in your application, all mapping to the
|
1372
|
+
# `Photos` controller:
|
1378
1373
|
#
|
1379
|
-
#
|
1380
|
-
#
|
1381
|
-
#
|
1382
|
-
#
|
1383
|
-
#
|
1384
|
-
#
|
1385
|
-
#
|
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
|
1386
1381
|
#
|
1387
1382
|
# Resources can also be nested infinitely by using this block syntax:
|
1388
1383
|
#
|
1389
|
-
#
|
1390
|
-
#
|
1391
|
-
#
|
1384
|
+
# resources :photos do
|
1385
|
+
# resources :comments
|
1386
|
+
# end
|
1392
1387
|
#
|
1393
1388
|
# This generates the following comments routes:
|
1394
1389
|
#
|
1395
|
-
#
|
1396
|
-
#
|
1397
|
-
#
|
1398
|
-
#
|
1399
|
-
#
|
1400
|
-
#
|
1401
|
-
#
|
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
|
1402
1397
|
#
|
1403
|
-
#
|
1404
|
-
# Takes same options as match
|
1398
|
+
# ### Options
|
1399
|
+
# Takes same options as [match](rdoc-ref:Base#match) as well as:
|
1405
1400
|
#
|
1406
|
-
#
|
1407
|
-
# Allows you to change the segment component of the
|
1408
|
-
#
|
1401
|
+
# :path_names
|
1402
|
+
# : Allows you to change the segment component of the `edit` and `new`
|
1403
|
+
# actions. Actions not specified are not changed.
|
1409
1404
|
#
|
1410
|
-
#
|
1405
|
+
# resources :posts, path_names: { new: "brand_new" }
|
1411
1406
|
#
|
1412
|
-
#
|
1407
|
+
# The above example will now change /posts/new to /posts/brand_new.
|
1413
1408
|
#
|
1414
|
-
#
|
1415
|
-
# Allows you to change the path prefix for the resource.
|
1409
|
+
# :path
|
1410
|
+
# : Allows you to change the path prefix for the resource.
|
1416
1411
|
#
|
1417
|
-
#
|
1412
|
+
# resources :posts, path: 'postings'
|
1418
1413
|
#
|
1419
|
-
#
|
1414
|
+
# The resource and all segments will now route to /postings instead of
|
1415
|
+
# /posts.
|
1420
1416
|
#
|
1421
|
-
#
|
1422
|
-
# Only generate routes for the given actions.
|
1417
|
+
# :only
|
1418
|
+
# : Only generate routes for the given actions.
|
1423
1419
|
#
|
1424
|
-
#
|
1425
|
-
#
|
1420
|
+
# resources :cows, only: :show
|
1421
|
+
# resources :cows, only: [:show, :index]
|
1426
1422
|
#
|
1427
|
-
#
|
1428
|
-
# Generate all routes except for the given actions.
|
1423
|
+
# :except
|
1424
|
+
# : Generate all routes except for the given actions.
|
1429
1425
|
#
|
1430
|
-
#
|
1431
|
-
#
|
1426
|
+
# resources :cows, except: :show
|
1427
|
+
# resources :cows, except: [:show, :index]
|
1432
1428
|
#
|
1433
|
-
#
|
1434
|
-
# Generates shallow routes for nested resource(s). When placed on a parent
|
1435
|
-
#
|
1429
|
+
# :shallow
|
1430
|
+
# : Generates shallow routes for nested resource(s). When placed on a parent
|
1431
|
+
# resource, generates shallow routes for all nested resources.
|
1436
1432
|
#
|
1437
|
-
#
|
1438
|
-
#
|
1439
|
-
#
|
1433
|
+
# resources :posts, shallow: true do
|
1434
|
+
# resources :comments
|
1435
|
+
# end
|
1440
1436
|
#
|
1441
|
-
#
|
1437
|
+
# Is the same as:
|
1442
1438
|
#
|
1443
|
-
#
|
1444
|
-
#
|
1445
|
-
#
|
1446
|
-
#
|
1439
|
+
# resources :posts do
|
1440
|
+
# resources :comments, except: [:show, :edit, :update, :destroy]
|
1441
|
+
# end
|
1442
|
+
# resources :comments, only: [:show, :edit, :update, :destroy]
|
1447
1443
|
#
|
1448
|
-
#
|
1449
|
-
#
|
1450
|
-
#
|
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`.
|
1451
1447
|
#
|
1452
|
-
#
|
1448
|
+
# Set `shallow: false` on a child resource to ignore a parent's shallow
|
1449
|
+
# parameter.
|
1453
1450
|
#
|
1454
|
-
#
|
1455
|
-
# Prefixes nested shallow routes with the specified path.
|
1451
|
+
# :shallow_path
|
1452
|
+
# : Prefixes nested shallow routes with the specified path.
|
1456
1453
|
#
|
1457
|
-
#
|
1458
|
-
#
|
1459
|
-
#
|
1460
|
-
#
|
1461
|
-
#
|
1454
|
+
# scope shallow_path: "sekret" do
|
1455
|
+
# resources :posts do
|
1456
|
+
# resources :comments, shallow: true
|
1457
|
+
# end
|
1458
|
+
# end
|
1462
1459
|
#
|
1463
|
-
#
|
1460
|
+
# The `comments` resource here will have the following routes generated for
|
1461
|
+
# it:
|
1464
1462
|
#
|
1465
|
-
#
|
1466
|
-
#
|
1467
|
-
#
|
1468
|
-
#
|
1469
|
-
#
|
1470
|
-
#
|
1471
|
-
#
|
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)
|
1472
1470
|
#
|
1473
|
-
#
|
1474
|
-
# Prefixes nested shallow route names with specified prefix.
|
1471
|
+
# :shallow_prefix
|
1472
|
+
# : Prefixes nested shallow route names with specified prefix.
|
1475
1473
|
#
|
1476
|
-
#
|
1477
|
-
#
|
1478
|
-
#
|
1479
|
-
#
|
1480
|
-
#
|
1474
|
+
# scope shallow_prefix: "sekret" do
|
1475
|
+
# resources :posts do
|
1476
|
+
# resources :comments, shallow: true
|
1477
|
+
# end
|
1478
|
+
# end
|
1481
1479
|
#
|
1482
|
-
#
|
1480
|
+
# The `comments` resource here will have the following routes generated for
|
1481
|
+
# it:
|
1483
1482
|
#
|
1484
|
-
#
|
1485
|
-
#
|
1486
|
-
#
|
1487
|
-
#
|
1488
|
-
#
|
1489
|
-
#
|
1490
|
-
#
|
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)
|
1491
1490
|
#
|
1492
|
-
#
|
1493
|
-
# Allows you to specify the default value for optional
|
1494
|
-
#
|
1491
|
+
# :format
|
1492
|
+
# : Allows you to specify the default value for optional `format` segment or
|
1493
|
+
# disable it by supplying `false`.
|
1495
1494
|
#
|
1496
|
-
#
|
1497
|
-
# 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.
|
1498
1497
|
#
|
1499
|
-
# === Examples
|
1500
1498
|
#
|
1501
|
-
#
|
1502
|
-
# resources :posts, module: "admin"
|
1499
|
+
# ### Examples
|
1503
1500
|
#
|
1504
|
-
#
|
1505
|
-
#
|
1501
|
+
# # routes call +Admin::PostsController+
|
1502
|
+
# resources :posts, module: "admin"
|
1503
|
+
#
|
1504
|
+
# # resource actions are at /admin/posts.
|
1505
|
+
# resources :posts, path: "admin/posts"
|
1506
1506
|
def resources(*resources, &block)
|
1507
1507
|
options = resources.extract_options!.dup
|
1508
1508
|
|
@@ -1535,16 +1535,15 @@ module ActionDispatch
|
|
1535
1535
|
|
1536
1536
|
# To add a route to the collection:
|
1537
1537
|
#
|
1538
|
-
#
|
1539
|
-
#
|
1540
|
-
#
|
1538
|
+
# resources :photos do
|
1539
|
+
# collection do
|
1540
|
+
# get 'search'
|
1541
|
+
# end
|
1541
1542
|
# end
|
1542
|
-
# end
|
1543
1543
|
#
|
1544
|
-
# This will enable
|
1545
|
-
#
|
1546
|
-
#
|
1547
|
-
# 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.
|
1548
1547
|
def collection(&block)
|
1549
1548
|
unless resource_scope?
|
1550
1549
|
raise ArgumentError, "can't use collection outside resource(s) scope"
|
@@ -1557,15 +1556,15 @@ module ActionDispatch
|
|
1557
1556
|
|
1558
1557
|
# To add a member route, add a member block into the resource block:
|
1559
1558
|
#
|
1560
|
-
#
|
1561
|
-
#
|
1562
|
-
#
|
1559
|
+
# resources :photos do
|
1560
|
+
# member do
|
1561
|
+
# get 'preview'
|
1562
|
+
# end
|
1563
1563
|
# end
|
1564
|
-
# end
|
1565
1564
|
#
|
1566
|
-
# This will recognize
|
1567
|
-
#
|
1568
|
-
#
|
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.
|
1569
1568
|
def member(&block)
|
1570
1569
|
unless resource_scope?
|
1571
1570
|
raise ArgumentError, "can't use member outside resource(s) scope"
|
@@ -1632,29 +1631,28 @@ module ActionDispatch
|
|
1632
1631
|
!parent_resource.singleton? && @scope[:shallow]
|
1633
1632
|
end
|
1634
1633
|
|
1635
|
-
# Loads another routes file with the given
|
1636
|
-
#
|
1637
|
-
#
|
1638
|
-
#
|
1639
|
-
#
|
1640
|
-
#
|
1641
|
-
#
|
1642
|
-
#
|
1643
|
-
#
|
1644
|
-
#
|
1645
|
-
#
|
1646
|
-
#
|
1647
|
-
#
|
1648
|
-
#
|
1649
|
-
#
|
1650
|
-
#
|
1651
|
-
#
|
1652
|
-
#
|
1653
|
-
#
|
1654
|
-
#
|
1655
|
-
#
|
1656
|
-
#
|
1657
|
-
# 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.
|
1658
1656
|
def draw(name)
|
1659
1657
|
path = @draw_paths.find do |_path|
|
1660
1658
|
File.exist? "#{_path}/#{name}.rb"
|
@@ -1671,12 +1669,12 @@ module ActionDispatch
|
|
1671
1669
|
instance_eval(File.read(route_path), route_path.to_s)
|
1672
1670
|
end
|
1673
1671
|
|
1674
|
-
# Matches a URL pattern to one or more routes.
|
1675
|
-
#
|
1672
|
+
# Matches a URL pattern to one or more routes. For more information, see
|
1673
|
+
# [match](rdoc-ref:Base#match).
|
1676
1674
|
#
|
1677
|
-
#
|
1678
|
-
#
|
1679
|
-
#
|
1675
|
+
# match 'path' => 'controller#action', via: :patch
|
1676
|
+
# match 'path', to: 'controller#action', via: :post
|
1677
|
+
# match 'path', 'otherpath', on: :member, via: :get
|
1680
1678
|
def match(path, *rest, &block)
|
1681
1679
|
if rest.empty? && Hash === path
|
1682
1680
|
options = path
|
@@ -1711,19 +1709,19 @@ module ActionDispatch
|
|
1711
1709
|
end
|
1712
1710
|
end
|
1713
1711
|
|
1714
|
-
# You can specify what
|
1712
|
+
# You can specify what Rails should route "/" to with the root method:
|
1715
1713
|
#
|
1716
|
-
#
|
1714
|
+
# root to: 'pages#main'
|
1717
1715
|
#
|
1718
|
-
# For options, see
|
1716
|
+
# For options, see `match`, as `root` uses it internally.
|
1719
1717
|
#
|
1720
1718
|
# You can also pass a string which will expand
|
1721
1719
|
#
|
1722
|
-
#
|
1720
|
+
# root 'pages#main'
|
1723
1721
|
#
|
1724
|
-
# You should put the root route at the top of
|
1725
|
-
#
|
1726
|
-
#
|
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.
|
1727
1725
|
def root(path, options = {})
|
1728
1726
|
if path.is_a?(String)
|
1729
1727
|
options[:to] = path
|
@@ -1901,9 +1899,9 @@ module ActionDispatch
|
|
1901
1899
|
candidate = action_name.select(&:present?).join("_")
|
1902
1900
|
|
1903
1901
|
unless candidate.empty?
|
1904
|
-
# If a name was not explicitly given, we check if it is valid
|
1905
|
-
#
|
1906
|
-
#
|
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.
|
1907
1905
|
if as.nil?
|
1908
1906
|
candidate unless !candidate.match?(/\A[_a-z]/i) || has_named_route?(candidate)
|
1909
1907
|
else
|
@@ -2026,7 +2024,7 @@ module ActionDispatch
|
|
2026
2024
|
name_for_action(options.delete(:as), action)
|
2027
2025
|
end
|
2028
2026
|
|
2029
|
-
path = Mapping.normalize_path
|
2027
|
+
path = Mapping.normalize_path URI::DEFAULT_PARSER.escape(path), formatted
|
2030
2028
|
ast = Journey::Parser.parse path
|
2031
2029
|
|
2032
2030
|
mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
@@ -2039,83 +2037,81 @@ module ActionDispatch
|
|
2039
2037
|
end
|
2040
2038
|
end
|
2041
2039
|
|
2042
|
-
# Routing Concerns allow you to declare common routes that can be reused
|
2043
|
-
#
|
2040
|
+
# Routing Concerns allow you to declare common routes that can be reused inside
|
2041
|
+
# others resources and routes.
|
2044
2042
|
#
|
2045
|
-
#
|
2046
|
-
#
|
2047
|
-
#
|
2043
|
+
# concern :commentable do
|
2044
|
+
# resources :comments
|
2045
|
+
# end
|
2048
2046
|
#
|
2049
|
-
#
|
2050
|
-
#
|
2051
|
-
#
|
2047
|
+
# concern :image_attachable do
|
2048
|
+
# resources :images, only: :index
|
2049
|
+
# end
|
2052
2050
|
#
|
2053
2051
|
# These concerns are used in Resources routing:
|
2054
2052
|
#
|
2055
|
-
#
|
2053
|
+
# resources :messages, concerns: [:commentable, :image_attachable]
|
2056
2054
|
#
|
2057
2055
|
# or in a scope or namespace:
|
2058
2056
|
#
|
2059
|
-
#
|
2060
|
-
#
|
2061
|
-
#
|
2057
|
+
# namespace :posts do
|
2058
|
+
# concerns :commentable
|
2059
|
+
# end
|
2062
2060
|
module Concerns
|
2063
2061
|
# Define a routing concern using a name.
|
2064
2062
|
#
|
2065
|
-
# Concerns may be defined inline, using a block, or handled by
|
2066
|
-
#
|
2063
|
+
# Concerns may be defined inline, using a block, or handled by another object,
|
2064
|
+
# by passing that object as the second parameter.
|
2067
2065
|
#
|
2068
|
-
# The concern object, if supplied, should respond to
|
2069
|
-
#
|
2066
|
+
# The concern object, if supplied, should respond to `call`, which will receive
|
2067
|
+
# two parameters:
|
2070
2068
|
#
|
2071
|
-
#
|
2072
|
-
#
|
2069
|
+
# * The current mapper
|
2070
|
+
# * A hash of options which the concern object may use
|
2073
2071
|
#
|
2074
|
-
# Options may also be used by concerns defined in a block by accepting
|
2075
|
-
#
|
2076
|
-
#
|
2077
|
-
#
|
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:
|
2078
2076
|
#
|
2079
|
-
#
|
2080
|
-
#
|
2081
|
-
#
|
2077
|
+
# concern :commentable do |options|
|
2078
|
+
# resources :comments, options
|
2079
|
+
# end
|
2082
2080
|
#
|
2083
|
-
#
|
2084
|
-
#
|
2085
|
-
#
|
2086
|
-
#
|
2087
|
-
#
|
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
|
2088
2086
|
#
|
2089
|
-
# Or, using a callable object, you might implement something more
|
2090
|
-
#
|
2091
|
-
# 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.
|
2092
2089
|
#
|
2093
|
-
#
|
2094
|
-
#
|
2095
|
-
#
|
2096
|
-
#
|
2097
|
-
#
|
2090
|
+
# # purchasable.rb
|
2091
|
+
# class Purchasable
|
2092
|
+
# def initialize(defaults = {})
|
2093
|
+
# @defaults = defaults
|
2094
|
+
# end
|
2098
2095
|
#
|
2099
|
-
#
|
2100
|
-
#
|
2101
|
-
#
|
2102
|
-
#
|
2103
|
-
#
|
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
|
2104
2102
|
# end
|
2105
|
-
# end
|
2106
2103
|
#
|
2107
|
-
#
|
2108
|
-
#
|
2104
|
+
# # routes.rb
|
2105
|
+
# concern :purchasable, Purchasable.new(returnable: true)
|
2109
2106
|
#
|
2110
|
-
#
|
2111
|
-
#
|
2112
|
-
#
|
2113
|
-
#
|
2114
|
-
#
|
2107
|
+
# resources :toys, concerns: :purchasable
|
2108
|
+
# resources :electronics, concerns: :purchasable
|
2109
|
+
# resources :pets do
|
2110
|
+
# concerns :purchasable, returnable: false
|
2111
|
+
# end
|
2115
2112
|
#
|
2116
|
-
# Any routing helpers can be used inside a concern. If using a
|
2117
|
-
#
|
2118
|
-
# <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`.
|
2119
2115
|
def concern(name, callable = nil, &block)
|
2120
2116
|
callable ||= lambda { |mapper, options| mapper.instance_exec(options, &block) }
|
2121
2117
|
@concerns[name] = callable
|
@@ -2123,15 +2119,15 @@ module ActionDispatch
|
|
2123
2119
|
|
2124
2120
|
# Use the named concerns
|
2125
2121
|
#
|
2126
|
-
#
|
2127
|
-
#
|
2128
|
-
#
|
2122
|
+
# resources :posts do
|
2123
|
+
# concerns :commentable
|
2124
|
+
# end
|
2129
2125
|
#
|
2130
2126
|
# Concerns also work in any routes helper that you want to use:
|
2131
2127
|
#
|
2132
|
-
#
|
2133
|
-
#
|
2134
|
-
#
|
2128
|
+
# namespace :posts do
|
2129
|
+
# concerns :commentable
|
2130
|
+
# end
|
2135
2131
|
def concerns(*args)
|
2136
2132
|
options = args.extract_options!
|
2137
2133
|
args.flatten.each do |name|
|
@@ -2145,53 +2141,55 @@ module ActionDispatch
|
|
2145
2141
|
end
|
2146
2142
|
|
2147
2143
|
module CustomUrls
|
2148
|
-
# Define custom URL helpers that will be added to the application's
|
2149
|
-
#
|
2150
|
-
#
|
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:
|
2151
2147
|
#
|
2152
|
-
#
|
2153
|
-
#
|
2154
|
-
#
|
2148
|
+
# direct :homepage do
|
2149
|
+
# "https://rubyonrails.org"
|
2150
|
+
# end
|
2155
2151
|
#
|
2156
|
-
#
|
2157
|
-
#
|
2158
|
-
#
|
2152
|
+
# direct :commentable do |model|
|
2153
|
+
# [ model, anchor: model.dom_id ]
|
2154
|
+
# end
|
2155
|
+
#
|
2156
|
+
# direct :main do
|
2157
|
+
# { controller: "pages", action: "index", subdomain: "www" }
|
2158
|
+
# end
|
2159
2159
|
#
|
2160
|
-
#
|
2161
|
-
#
|
2162
|
-
#
|
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:
|
2163
2163
|
#
|
2164
|
-
#
|
2165
|
-
#
|
2166
|
-
#
|
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
|
2167
2169
|
#
|
2168
|
-
# * A string, which is treated as a generated URL
|
2169
|
-
# * A hash, e.g. <tt>{ controller: "pages", action: "index" }</tt>
|
2170
|
-
# * An array, which is passed to +polymorphic_url+
|
2171
|
-
# * An Active Model instance
|
2172
|
-
# * An Active Model class
|
2173
2170
|
#
|
2174
|
-
# NOTE: Other URL helpers can be called in the block but be careful not to
|
2175
|
-
# your custom URL helper again otherwise it will result in a stack
|
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.
|
2176
2174
|
#
|
2177
|
-
# You can also specify default options that will be passed through to
|
2178
|
-
#
|
2175
|
+
# You can also specify default options that will be passed through to your URL
|
2176
|
+
# helper definition, e.g:
|
2179
2177
|
#
|
2180
|
-
#
|
2181
|
-
#
|
2182
|
-
#
|
2178
|
+
# direct :browse, page: 1, size: 10 do |options|
|
2179
|
+
# [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
|
2180
|
+
# end
|
2183
2181
|
#
|
2184
|
-
# In this instance the
|
2185
|
-
#
|
2186
|
-
#
|
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:
|
2187
2185
|
#
|
2188
|
-
#
|
2186
|
+
# Rails.application.routes.url_helpers.browse_path
|
2189
2187
|
#
|
2190
|
-
# then it will raise a
|
2188
|
+
# then it will raise a `NameError`. Because of this you need to be aware of the
|
2191
2189
|
# context in which you will use your custom URL helper when defining it.
|
2192
2190
|
#
|
2193
|
-
# NOTE: The
|
2194
|
-
#
|
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.
|
2195
2193
|
def direct(name, options = {}, &block)
|
2196
2194
|
unless @scope.root?
|
2197
2195
|
raise RuntimeError, "The direct method can't be used inside a routes scope block"
|
@@ -2200,50 +2198,50 @@ module ActionDispatch
|
|
2200
2198
|
@set.add_url_helper(name, options, &block)
|
2201
2199
|
end
|
2202
2200
|
|
2203
|
-
# Define custom polymorphic mappings of models to URLs. This alters the
|
2204
|
-
#
|
2205
|
-
#
|
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:
|
2206
2204
|
#
|
2207
|
-
#
|
2205
|
+
# resource :basket
|
2208
2206
|
#
|
2209
|
-
#
|
2210
|
-
#
|
2211
|
-
#
|
2207
|
+
# resolve "Basket" do
|
2208
|
+
# [:basket]
|
2209
|
+
# end
|
2212
2210
|
#
|
2213
|
-
# This will now generate "/basket" when a
|
2214
|
-
#
|
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".
|
2215
2213
|
#
|
2216
|
-
# NOTE: This custom behavior only applies to simple polymorphic URLs where
|
2217
|
-
#
|
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:
|
2218
2216
|
#
|
2219
|
-
#
|
2220
|
-
#
|
2221
|
-
#
|
2222
|
-
#
|
2223
|
-
#
|
2217
|
+
# # config/routes.rb
|
2218
|
+
# resource :profile
|
2219
|
+
# namespace :admin do
|
2220
|
+
# resources :users
|
2221
|
+
# end
|
2224
2222
|
#
|
2225
|
-
#
|
2223
|
+
# resolve("User") { [:profile] }
|
2226
2224
|
#
|
2227
|
-
#
|
2228
|
-
#
|
2229
|
-
#
|
2225
|
+
# # app/views/application/_menu.html.erb
|
2226
|
+
# link_to "Profile", @current_user
|
2227
|
+
# link_to "Profile", [:admin, @current_user]
|
2230
2228
|
#
|
2231
|
-
# The first
|
2232
|
-
#
|
2229
|
+
# The first `link_to` will generate "/profile" but the second will generate the
|
2230
|
+
# standard polymorphic URL of "/admin/users/1".
|
2233
2231
|
#
|
2234
|
-
# You can pass options to a polymorphic mapping - the arity for the block
|
2235
|
-
#
|
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:
|
2236
2234
|
#
|
2237
|
-
#
|
2238
|
-
#
|
2239
|
-
#
|
2235
|
+
# resolve "Basket", anchor: "items" do |basket, options|
|
2236
|
+
# [:basket, options]
|
2237
|
+
# end
|
2240
2238
|
#
|
2241
|
-
# This generates the URL "/basket#items" because when the last item in an
|
2242
|
-
#
|
2243
|
-
#
|
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.
|
2244
2242
|
#
|
2245
|
-
# NOTE: The
|
2246
|
-
#
|
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.
|
2247
2245
|
def resolve(*args, &block)
|
2248
2246
|
unless @scope.root?
|
2249
2247
|
raise RuntimeError, "The resolve method can't be used inside a routes scope block"
|