1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #40593 from jonathanhefner/guide-routing-link-api

Link to API docs in Routing guide [ci-skip]
This commit is contained in:
Jonathan Hefner 2020-11-15 11:21:04 -06:00 committed by GitHub
commit eb7cf21a96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -83,7 +83,9 @@ NOTE: The `Rails.application.routes.draw do ... end` block that wraps your route
Resource Routing: the Rails Default 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 ### 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 ### 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 ```ruby
namespace :admin do 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) | | PATCH/PUT | /admin/articles/:id | admin/articles#update | admin_article_path(:id) |
| DELETE | /admin/articles/:id | admin/articles#destroy | 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 ```ruby
scope module: 'admin' do scope module: 'admin' do
@ -228,13 +230,13 @@ scope module: 'admin' do
end end
``` ```
or, for a single case: This can also be done for a single route:
```ruby ```ruby
resources :articles, module: 'admin' 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 ```ruby
scope '/admin' do scope '/admin' do
@ -242,7 +244,7 @@ scope '/admin' do
end end
``` ```
or, for a single case: This can also be done for a single route:
```ruby ```ruby
resources :articles, path: '/admin/articles' 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'`._ 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 ### Nested Resources
It's common to have resources that are logically children of other resources. For example, suppose your application includes these models: 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
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 ```ruby
concern :commentable do concern :commentable do
@ -440,7 +445,7 @@ resources :articles do
end 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 ```ruby
namespace :articles do namespace :articles do
@ -448,6 +453,9 @@ namespace :articles do
end 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 ### 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: 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 #### 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 ```ruby
resources :photos do 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. 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 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 . If you don't have multiple `member` routes, you can also pass `:on` to a
route, eliminating the block: 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`. 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 #### Adding Collection Routes
To add a route to the collection: To add a route to the collection, use a [`collection`][] block:
```ruby ```ruby
resources :photos do 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. 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 #### Adding Routes for Additional New Actions
To add an alternate new action using the `:on` shortcut: 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"`. 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 ```ruby
defaults format: :json do 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. 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 ### Naming Routes
You can specify a name for any route using the `:as` option: 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 ### 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 ```ruby
match 'photos', to: 'photos#show', via: [:get, :post] 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. 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 ### Segment Constraints
You can use the `:constraints` option to enforce a format for a dynamic segment: 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' } 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 ```ruby
namespace :admin do 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. 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 ### 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: 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 ### 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 ```ruby
get '/stories', to: redirect('/articles') 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. 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 ### 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: 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 If you would prefer to have your Rack application receive requests at the root
path instead, use `mount`: path instead, use [`mount`][]:
```ruby ```ruby
mount AdminApp, at: '/admin' mount AdminApp, at: '/admin'
``` ```
[`mount`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-mount
### Using `root` ### 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 ```ruby
root to: 'pages#main' root to: 'pages#main'
@ -898,6 +926,8 @@ end
root to: "home#index" root to: "home#index"
``` ```
[`root`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-root
### Unicode Character Routes ### Unicode Character Routes
You can specify unicode character routes directly. For example: You can specify unicode character routes directly. For example:
@ -908,7 +938,7 @@ get 'こんにちは', to: 'welcome#index'
### Direct Routes ### Direct Routes
You can create custom URL helpers directly. For example: You can create custom URL helpers directly by calling [`direct`][]. For example:
```ruby ```ruby
direct :homepage do direct :homepage do
@ -931,9 +961,11 @@ direct :main do
end end
``` ```
[`direct`]: https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/CustomUrls.html#method-i-direct
### Using `resolve` ### 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 ``` ruby
resource :basket resource :basket
@ -949,10 +981,12 @@ resolve("Basket") { [:basket] }
This will generate the singular URL `/basket` instead of the usual `/baskets/:id`. 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 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 ### Specifying a Controller to Use
@ -1139,7 +1173,7 @@ Rails now creates routes to the `CategoriesController`.
### Overriding the Singular Form ### 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 ```ruby
ActiveSupport::Inflector.inflections do |inflect| ActiveSupport::Inflector.inflections do |inflect|
@ -1147,6 +1181,8 @@ ActiveSupport::Inflector.inflections do |inflect|
end end
``` ```
[`inflections`]: https://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-inflections
### Using `:as` in Nested Resources ### Using `:as` in Nested Resources
The `:as` option overrides the automatically-generated name for the resource in nested route helpers. For example: 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, If you work in a large application with thousands of routes,
a single `config/routes.rb` file can become cumbersome and hard to read. 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 ```ruby
# config/routes.rb # 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. 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 ### 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... 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 ### 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_generates`][]
* `assert_recognizes` * [`assert_recognizes`][]
* `assert_routing` * [`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 #### 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 ```ruby
assert_generates '/photos/1', { controller: 'photos', action: 'show', id: '1' } 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 #### 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 ```ruby
assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1') 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
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 ```ruby
assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' }) assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' })