Skip to content

Commit

Permalink
Merge pull request #40593 from jonathanhefner/guide-routing-link-api
Browse files Browse the repository at this point in the history
Link to API docs in Routing guide [ci-skip]
  • Loading branch information
jonathanhefner committed Nov 15, 2020
2 parents 8d41b48 + eae8302 commit eb7cf21
Showing 1 changed file with 71 additions and 29 deletions.
100 changes: 71 additions & 29 deletions guides/source/routing.md
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -220,29 +222,29 @@ 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
resources :articles, :comments
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
resources :articles, :comments
end
```

or, for a single case:
This can also be done for a single route:

```ruby
resources :articles, path: '/admin/articles'
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -440,14 +445,17 @@ 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
concerns :commentable
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:
Expand Down Expand Up @@ -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
Expand All @@ -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:

Expand All @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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]
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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')
Expand All @@ -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:
Expand All @@ -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'
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -1139,14 +1173,16 @@ 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|
inflect.irregular 'tooth', 'teeth'
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:
Expand Down Expand Up @@ -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
Expand All @@ -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...
Expand Down Expand Up @@ -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' }
Expand All @@ -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')
Expand All @@ -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' })
Expand Down

0 comments on commit eb7cf21

Please sign in to comment.