From eae8302718d8abdaf09bed10cb8e666bcbbd25d3 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 9 Nov 2020 15:55:18 -0600 Subject: [PATCH] Link to API docs in Routing guide [ci-skip] This links the first mention of each method to its API documentation, similar to a Wikipedia article. Some subsequent mentions are also linked, when it suits the surrounding text. This also modifies the text in a few places to ensure that methods are explicitly mentioned (and linked) before they appear in code examples. --- guides/source/routing.md | 100 +++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/guides/source/routing.md b/guides/source/routing.md index 0c7e0adfb4..816ecb0129 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -83,7 +83,9 @@ NOTE: The `Rails.application.routes.draw do ... end` block that wraps your route Resource Routing: the Rails Default ----------------------------------- -Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your `index`, `show`, `new`, `edit`, `create`, `update` and `destroy` actions, a resourceful route declares them in a single line of code. +Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. A single call to [`resources`][] can declare all of the necessary routes for your `index`, `show`, `new`, `edit`, `create`, `update` and `destroy` actions. + +[`resources`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources ### Resources on the Web @@ -200,7 +202,7 @@ As with plural resources, the same helpers ending in `_url` will also include th ### Controller Namespaces and Routing -You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an `Admin::` namespace. You would place these controllers under the `app/controllers/admin` directory, and you can group them together in your router: +You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an `Admin::` namespace, and place these controllers under the `app/controllers/admin` directory. You can route to such a group by using a [`namespace`][] block: ```ruby namespace :admin do @@ -220,7 +222,7 @@ This will create a number of routes for each of the `articles` and `comments` co | PATCH/PUT | /admin/articles/:id | admin/articles#update | admin_article_path(:id) | | DELETE | /admin/articles/:id | admin/articles#destroy | admin_article_path(:id) | -If you want to route `/articles` (without the prefix `/admin`) to `Admin::ArticlesController`, you could use: +If instead you want to route `/articles` (without the prefix `/admin`) to `Admin::ArticlesController`, you can specify the module with a [`scope`][] block: ```ruby scope module: 'admin' do @@ -228,13 +230,13 @@ scope module: 'admin' do end ``` -or, for a single case: +This can also be done for a single route: ```ruby resources :articles, module: 'admin' ``` -If you want to route `/admin/articles` to `ArticlesController` (without the `Admin::` module prefix), you could use: +If instead you want to route `/admin/articles` to `ArticlesController` (without the `Admin::` module prefix), you can specify the path with a `scope` block: ```ruby scope '/admin' do @@ -242,7 +244,7 @@ scope '/admin' do end ``` -or, for a single case: +This can also be done for a single route: ```ruby resources :articles, path: '/admin/articles' @@ -262,6 +264,9 @@ In each of these cases, the named routes remain the same as if you did not use ` TIP: _If you need to use a different controller namespace inside a `namespace` block you can specify an absolute controller path, e.g: `get '/foo', to: '/foo#index'`._ +[`namespace`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-namespace +[`scope`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-scope + ### Nested Resources It's common to have resources that are logically children of other resources. For example, suppose your application includes these models: @@ -407,7 +412,7 @@ The comments resource here will have the following routes generated for it: ### Routing Concerns -Routing concerns allow you to declare common routes that can be reused inside other resources and routes. To define a concern: +Routing concerns allow you to declare common routes that can be reused inside other resources and routes. To define a concern, use a [`concern`][] block: ```ruby concern :commentable do @@ -440,7 +445,7 @@ resources :articles do end ``` -Also you can use them in any place that you want inside the routes, for example in a `scope` or `namespace` call: +You can also use them anywhere by calling [`concerns`][]. For example, in a `scope` or `namespace` block: ```ruby namespace :articles do @@ -448,6 +453,9 @@ namespace :articles do end ``` +[`concern`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Concerns.html#method-i-concern +[`concerns`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Concerns.html#method-i-concerns + ### Creating Paths and URLs from Objects In addition to using the routing helpers, Rails can also create paths and URLs from an array of parameters. For example, suppose you have this set of routes: @@ -496,7 +504,7 @@ You are not limited to the seven routes that RESTful routing creates by default. #### Adding Member Routes -To add a member route, just add a `member` block into the resource block: +To add a member route, just add a [`member`][] block into the resource block: ```ruby resources :photos do @@ -509,7 +517,7 @@ end This will recognize `/photos/1/preview` with GET, and route to the `preview` action of `PhotosController`, with the resource id value passed in `params[:id]`. It will also create the `preview_photo_url` and `preview_photo_path` helpers. Within the block of member routes, each route name specifies the HTTP verb that -will be recognized. You can use `get`, `patch`, `put`, `post`, or `delete` here +will be recognized. You can use [`get`][], [`patch`][], [`put`][], [`post`][], or [`delete`][] here . If you don't have multiple `member` routes, you can also pass `:on` to a route, eliminating the block: @@ -521,9 +529,17 @@ end You can leave out the `:on` option, this will create the same member route except that the resource id value will be available in `params[:photo_id]` instead of `params[:id]`. Route helpers will also be renamed from `preview_photo_url` and `preview_photo_path` to `photo_preview_url` and `photo_preview_path`. +[`delete`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-delete +[`get`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-get +[`member`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-member +[`patch`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-patch +[`post`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-post +[`put`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-put +[`put`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-put + #### Adding Collection Routes -To add a route to the collection: +To add a route to the collection, use a [`collection`][] block: ```ruby resources :photos do @@ -545,6 +561,8 @@ end NOTE: If you're defining additional resource routes with a symbol as the first positional argument, be mindful that it is not equivalent to using a string. Symbols infer controller actions while strings infer paths. +[`collection`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-collection + #### Adding Routes for Additional New Actions To add an alternate new action using the `:on` shortcut: @@ -620,7 +638,7 @@ get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' } Rails would match `photos/12` to the `show` action of `PhotosController`, and set `params[:format]` to `"jpg"`. -You can also use `defaults` in a block format to define the defaults for multiple items: +You can also use a [`defaults`][] block to define the defaults for multiple items: ```ruby defaults format: :json do @@ -630,6 +648,8 @@ end NOTE: You cannot override defaults via query parameters - this is for security reasons. The only defaults that can be overridden are dynamic segments via substitution in the URL path. +[`defaults`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-defaults + ### Naming Routes You can specify a name for any route using the `:as` option: @@ -651,7 +671,7 @@ This will define a `user_path` method that will be available in controllers, hel ### HTTP Verb Constraints -In general, you should use the `get`, `post`, `put`, `patch` and `delete` methods to constrain a route to a particular verb. You can use the `match` method with the `:via` option to match multiple verbs at once: +In general, you should use the [`get`][], [`post`][], [`put`][], [`patch`][], and [`delete`][] methods to constrain a route to a particular verb. You can use the [`match`][] method with the `:via` option to match multiple verbs at once: ```ruby match 'photos', to: 'photos#show', via: [:get, :post] @@ -667,6 +687,8 @@ NOTE: Routing both `GET` and `POST` requests to a single action has security imp NOTE: `GET` in Rails won't check for CSRF token. You should never write to the database from `GET` requests, for more information see the [security guide](security.html#csrf-countermeasures) on CSRF countermeasures. +[`match`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-match + ### Segment Constraints You can use the `:constraints` option to enforce a format for a dynamic segment: @@ -706,7 +728,7 @@ You specify a request-based constraint the same way that you specify a segment c get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' } ``` -You can also specify constraints in a block form: +You can also specify constraints by using a [`constraints`][] block: ```ruby namespace :admin do @@ -720,6 +742,8 @@ NOTE: Request constraints work by calling a method on the [Request object](actio NOTE: There is an exception for the `format` constraint: while it's a method on the Request object, it's also an implicit optional parameter on every path. Segment constraints take precedence and the `format` constraint is only applied as such when enforced through a hash. For example, `get 'foo', constraints: { format: 'json' }` will match `GET /foo` because the format is optional by default. However, you can [use a lambda](#advanced-constraints) like in `get 'foo', constraints: lambda { |req| req.format == :json }` and the route will only match explicit JSON requests. +[`constraints`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-constraints + ### Advanced Constraints If you have a more advanced constraint, you can provide an object that responds to `matches?` that Rails should use. Let's say you wanted to route all users on a restricted list to the `RestrictedListController`. You could do: @@ -821,7 +845,7 @@ get '*pages', to: 'pages#show', format: true ### Redirection -You can redirect any path to another path using the `redirect` helper in your router: +You can redirect any path to another path using the [`redirect`][] helper in your router: ```ruby get '/stories', to: redirect('/articles') @@ -848,6 +872,8 @@ get '/stories/:name', to: redirect('/articles/%{name}', status: 302) In all of these cases, if you don't provide the leading host (`http://www.example.com`), Rails will take those details from the current request. +[`redirect`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Redirection.html#method-i-redirect + ### Routing to Rack Applications Instead of a String like `'articles#index'`, which corresponds to the `index` action in the `ArticlesController`, you can specify any [Rack application](rails_on_rack.html) as the endpoint for a matcher: @@ -869,15 +895,17 @@ match '/admin', to: AdminApp, via: :all ``` If you would prefer to have your Rack application receive requests at the root -path instead, use `mount`: +path instead, use [`mount`][]: ```ruby mount AdminApp, at: '/admin' ``` +[`mount`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-mount + ### Using `root` -You can specify what Rails should route `'/'` to with the `root` method: +You can specify what Rails should route `'/'` to with the [`root`][] method: ```ruby root to: 'pages#main' @@ -898,6 +926,8 @@ end root to: "home#index" ``` +[`root`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-root + ### Unicode Character Routes You can specify unicode character routes directly. For example: @@ -908,7 +938,7 @@ get 'こんにちは', to: 'welcome#index' ### Direct Routes -You can create custom URL helpers directly. For example: +You can create custom URL helpers directly by calling [`direct`][]. For example: ```ruby direct :homepage do @@ -931,9 +961,11 @@ direct :main do end ``` +[`direct`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/CustomUrls.html#method-i-direct + ### Using `resolve` -The `resolve` method allows customizing polymorphic mapping of models. For example: +The [`resolve`][] method allows customizing polymorphic mapping of models. For example: ``` ruby resource :basket @@ -949,10 +981,12 @@ resolve("Basket") { [:basket] } This will generate the singular URL `/basket` instead of the usual `/baskets/:id`. +[`resolve`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/CustomUrls.html#method-i-resolve + Customizing Resourceful Routes ------------------------------ -While the default routes and helpers generated by `resources :articles` will usually serve you well, you may want to customize them in some way. Rails allows you to customize virtually any generic part of the resourceful helpers. +While the default routes and helpers generated by [`resources`][] will usually serve you well, you may want to customize them in some way. Rails allows you to customize virtually any generic part of the resourceful helpers. ### Specifying a Controller to Use @@ -1139,7 +1173,7 @@ Rails now creates routes to the `CategoriesController`. ### Overriding the Singular Form -If you want to define the singular form of a resource, you should add additional rules to the `Inflector`: +If you want to define the singular form of a resource, you should add additional rules to the `Inflector` via [`inflections`][]: ```ruby ActiveSupport::Inflector.inflections do |inflect| @@ -1147,6 +1181,8 @@ ActiveSupport::Inflector.inflections do |inflect| end ``` +[`inflections`]: https://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-inflections + ### Using `:as` in Nested Resources The `:as` option overrides the automatically-generated name for the resource in nested route helpers. For example: @@ -1201,7 +1237,7 @@ Breaking up *very* large route file into multiple small ones: If you work in a large application with thousands of routes, a single `config/routes.rb` file can become cumbersome and hard to read. -Rails offers a way to break a gigantic single `routes.rb` file into multiple small ones using the `draw` macro. +Rails offers a way to break a gigantic single `routes.rb` file into multiple small ones using the [`draw`][] macro. ```ruby # config/routes.rb @@ -1225,6 +1261,8 @@ The file needs to be located inside the `config/routes` directory or any sub-dir You can use the normal routing DSL inside the `admin.rb` routing file, **however** you shouldn't surround it with the `Rails.application.routes.draw` block like you did in the main `config/routes.rb` file. +[`draw`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-draw + ### When to use and not use this feature Drawing routes from external files can be very useful to organise a large set of routes into multiple organised ones. You could have a `admin.rb` route that contains all the routes for the admin area, another `api.rb` file to route API related resources etc... @@ -1305,15 +1343,19 @@ TIP: You'll find that the output from `bin/rails routes` is much more readable i ### Testing Routes -Routes should be included in your testing strategy (just like the rest of your application). Rails offers three [built-in assertions](https://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html) designed to make testing routes simpler: +Routes should be included in your testing strategy (just like the rest of your application). Rails offers three built-in assertions designed to make testing routes simpler: -* `assert_generates` -* `assert_recognizes` -* `assert_routing` +* [`assert_generates`][] +* [`assert_recognizes`][] +* [`assert_routing`][] + +[`assert_generates`]: https://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_generates +[`assert_recognizes`]: https://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes +[`assert_routing`]: https://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_routing #### The `assert_generates` Assertion -`assert_generates` asserts that a particular set of options generate a particular path and can be used with default routes or custom routes. For example: +[`assert_generates`][] asserts that a particular set of options generate a particular path and can be used with default routes or custom routes. For example: ```ruby assert_generates '/photos/1', { controller: 'photos', action: 'show', id: '1' } @@ -1322,7 +1364,7 @@ assert_generates '/about', controller: 'pages', action: 'about' #### The `assert_recognizes` Assertion -`assert_recognizes` is the inverse of `assert_generates`. It asserts that a given path is recognized and routes it to a particular spot in your application. For example: +[`assert_recognizes`][] is the inverse of `assert_generates`. It asserts that a given path is recognized and routes it to a particular spot in your application. For example: ```ruby assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1') @@ -1336,7 +1378,7 @@ assert_recognizes({ controller: 'photos', action: 'create' }, { path: 'photos', #### The `assert_routing` Assertion -The `assert_routing` assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of `assert_generates` and `assert_recognizes`: +The [`assert_routing`][] assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of `assert_generates` and `assert_recognizes`: ```ruby assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' })