routing.textile 36.3 KB
Newer Older
1 2 3 4
h2. Rails Routing from the Outside In

This guide covers the user-facing features of Rails routing. By referring to this guide, you will be able to:

5
* Understand the code in +routes.rb+
6
* Construct your own routes, using either the preferred resourceful style or the <tt>match</tt> method
7
* Identify what parameters to expect an action to receive
8
* Automatically create paths and URLs using route helpers
9
* Use advanced techniques such as constraints and Rack endpoints
10 11 12

endprologue.

13
h3. The Purpose of the Rails Router
14

15
The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views.
16 17 18

h4. Connecting URLs to Code

19
When your Rails application receives an incoming request
20

21
<plain>
22
GET /patients/17
23
</plain>
24

25
it asks the router to match it to a controller action. If the first matching route is
26 27

<ruby>
28
get "/patients/:id" => "patients#show"
29 30
</ruby>

31
the request is dispatched to the +patients+ controller's +show+ action with <tt>{ :id => "17" }</tt> in +params+.
32

33
h4. Generating Paths and URLs from Code
34

35 36 37 38 39 40 41
You can also generate paths and URLs.  If the route above is modified to be

<ruby>
get "/patients/:id" => "patients#show", :as => "patient"
</ruby>

If your application contains this code:
42

43
<ruby>
44
@patient = Patient.find(17)
45 46
</ruby>

47
<erb>
E
eparreno 已提交
48
<%= link_to "Patient Record", patient_path(@patient) %>
49
</erb>
50

E
eparreno 已提交
51
The router will generate the path +/patients/17+. This reduces the brittleness of your view and makes your code easier to understand. Note that the id does not need to be specified in the route helper.
52

53
h3. Resource Routing: the Rails Default
54

55
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.
56

57
h4. Resources on the Web
58

59
Browsers request pages from Rails by making a request for a URL using a specific HTTP method, such as +GET+, +POST+, +PATCH+, +PUT+ and +DELETE+. Each method is a request to perform an operation on the resource. A resource route maps a number of related requests to actions in a single controller.
60

61
When your Rails application receives an incoming request for
62

63 64 65
<plain>
DELETE /photos/17
</plain>
66

67
it asks the router to map it to a controller action. If the first matching route is
68 69

<ruby>
70
resources :photos
71 72
</ruby>

73
Rails would dispatch that request to the +destroy+ method on the +photos+ controller with <tt>{ :id => "17" }</tt> in +params+.
74 75 76

h4. CRUD, Verbs, and Actions

77
In Rails, a resourceful route provides a mapping between HTTP verbs and URLs to controller actions. By convention, each action also maps to particular CRUD operations in a database. A single entry in the routing file, such as
78 79

<ruby>
80
resources :photos
81 82
</ruby>

83
creates seven different routes in your application, all mapping to the +Photos+ controller:
84

S
Santiago Pastorino 已提交
85 86 87 88 89 90
|_. HTTP Verb |_.Path            |_.action |_.used for                                   |
|GET          |/photos           |index    |display a list of all photos                 |
|GET          |/photos/new       |new      |return an HTML form for creating a new photo |
|POST         |/photos           |create   |create a new photo                           |
|GET          |/photos/:id       |show     |display a specific photo                     |
|GET          |/photos/:id/edit  |edit     |return an HTML form for editing a photo      |
91
|PATCH/PUT    |/photos/:id       |update   |update a specific photo                      |
S
Santiago Pastorino 已提交
92
|DELETE       |/photos/:id       |destroy  |delete a specific photo                      |
93

94
NOTE: Rails routes are matched in the order they are specified, so if you have a +resources :photos+ above a +get 'photos/poll'+ the +show+ action's route for the +resources+ line will be matched before the +get+ line. To fix this, move the +get+ line *above* the +resources+ line so that it is matched first.
95

96
h4. Paths and URLs
97

98
Creating a resourceful route will also expose a number of helpers to the controllers in your application. In the case of +resources :photos+:
99

100 101
* +photos_path+ returns +/photos+
* +new_photo_path+ returns +/photos/new+
102 103
* +edit_photo_path(:id)+ returns +/photos/:id/edit+ (for instance, +edit_photo_path(10)+ returns +/photos/10/edit+)
* +photo_path(:id)+ returns +/photos/:id+ (for instance, +photo_path(10)+ returns +/photos/10+)
104

105
Each of these helpers has a corresponding +_url+ helper (such as +photos_url+) which returns the same path prefixed with the current host, port and path prefix.
106

107
NOTE: Because the router uses the HTTP verb and URL to match inbound requests, four URLs map to seven different actions.
108 109 110

h4. Defining Multiple Resources at the Same Time

111
If you need to create routes for more than one resource, you can save a bit of typing by defining them all with a single call to +resources+:
112 113

<ruby>
114
resources :photos, :books, :videos
115 116
</ruby>

117
This works exactly the same as
118 119

<ruby>
120 121 122
resources :photos
resources :books
resources :videos
123 124 125 126
</ruby>

h4. Singular Resources

127
Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like +/profile+ to always show the profile of the currently logged in user. In this case, you can use a singular resource to map +/profile+ (rather than +/profile/:id+) to the +show+ action.
128

129
<ruby>
130
get "profile" => "users#show"
131 132 133 134
</ruby>

This resourceful route

135
<ruby>
136
resource :geocoder
137 138
</ruby>

139
creates six different routes in your application, all mapping to the +Geocoders+ controller:
140

S
Santiago Pastorino 已提交
141 142 143 144 145
|_.HTTP Verb |_.Path         |_.action |_.used for                                    |
|GET         |/geocoder/new  |new      |return an HTML form for creating the geocoder |
|POST        |/geocoder      |create   |create the new geocoder                       |
|GET         |/geocoder      |show     |display the one and only geocoder resource    |
|GET         |/geocoder/edit |edit     |return an HTML form for editing the geocoder  |
146
|PATCH/PUT   |/geocoder      |update   |update the one and only geocoder resource     |
S
Santiago Pastorino 已提交
147
|DELETE      |/geocoder      |destroy  |delete the geocoder resource                  |
148

149
NOTE: Because you might want to use the same controller for a singular route (+/account+) and a plural route (+/accounts/45+), singular resources map to plural controllers.
150

151
A singular resourceful route generates these helpers:
152

153 154 155
* +new_geocoder_path+ returns +/geocoder/new+
* +edit_geocoder_path+ returns +/geocoder/edit+
* +geocoder_path+ returns +/geocoder+
156

157
As with plural resources, the same helpers ending in +_url+ will also include the host, port and path prefix.
158 159 160

h4. Controller Namespaces and Routing

161
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:
162 163

<ruby>
164
namespace :admin do
165
  resources :posts, :comments
166 167 168
end
</ruby>

169
This will create a number of routes for each of the +posts+ and +comments+ controller. For +Admin::PostsController+, Rails will create:
170

171 172 173 174 175 176
|_.HTTP Verb |_.Path                |_.action |_.named helper             |
|GET         |/admin/posts          |index    | admin_posts_path          |
|GET         |/admin/posts/new      |new      | new_admin_post_path       |
|POST        |/admin/posts          |create   | admin_posts_path          |
|GET         |/admin/posts/:id      |show     | admin_post_path(:id)      |
|GET         |/admin/posts/:id/edit |edit     | edit_admin_post_path(:id) |
177
|PATCH/PUT   |/admin/posts/:id      |update   | admin_post_path(:id)      |
178
|DELETE      |/admin/posts/:id      |destroy  | admin_post_path(:id)      |
179

180
If you want to route +/posts+ (without the prefix +/admin+) to +Admin::PostsController+, you could use
181 182

<ruby>
183 184 185
scope :module => "admin" do
  resources :posts, :comments
end
186 187
</ruby>

188
or, for a single case
189 190

<ruby>
191
resources :posts, :module => "admin"
192 193
</ruby>

194
If you want to route +/admin/posts+ to +PostsController+ (without the +Admin::+ module prefix), you could use
195 196

<ruby>
197 198 199
scope "/admin" do
  resources :posts, :comments
end
200 201
</ruby>

202
or, for a single case
203 204

<ruby>
205
resources :posts, :path => "/admin/posts"
206 207
</ruby>

208
In each of these cases, the named routes remain the same as if you did not use +scope+. In the last case, the following paths map to +PostsController+:
209

S
Santiago Pastorino 已提交
210 211
|_.HTTP Verb |_.Path               |_.action |_.named helper      |
|GET         |/admin/posts         |index    | posts_path         |
212
|GET         |/admin/posts/new     |new      | new_post_path      |
S
Santiago Pastorino 已提交
213
|POST        |/admin/posts         |create   | posts_path         |
214 215
|GET         |/admin/posts/:id     |show     | post_path(:id)     |
|GET         |/admin/posts/:id/edit|edit     | edit_post_path(:id)|
216
|PATCH/PUT   |/admin/posts/:id     |update   | post_path(:id)     |
217
|DELETE      |/admin/posts/:id     |destroy  | post_path(:id)     |
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232
h4. Nested Resources

It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:

<ruby>
class Magazine < ActiveRecord::Base
  has_many :ads
end

class Ad < ActiveRecord::Base
  belongs_to :magazine
end
</ruby>

233
Nested routes allow you to capture this relationship in your routing. In this case, you could include this route declaration:
234 235

<ruby>
236 237
resources :magazines do
  resources :ads
238 239 240
end
</ruby>

241
In addition to the routes for magazines, this declaration will also route ads to an +AdsController+. The ad URLs require a magazine:
242

243 244 245 246 247 248 249 250
|_.HTTP Verb |_.Path                               |_.action |_.used for                                                                 |
|GET         |/magazines/:magazine_id/ads          |index    |display a list of all ads for a specific magazine                          |
|GET         |/magazines/:magazine_id/ads/new      |new      |return an HTML form for creating a new ad belonging to a specific magazine |
|POST        |/magazines/:magazine_id/ads          |create   |create a new ad belonging to a specific magazine                           |
|GET         |/magazines/:magazine_id/ads/:id      |show     |display a specific ad belonging to a specific magazine                     |
|GET         |/magazines/:magazine_id/ads/:id/edit |edit     |return an HTML form for editing an ad belonging to a specific magazine     |
|PATCH/PUT   |/magazines/:magazine_id/ads/:id      |update   |update a specific ad belonging to a specific magazine                      |
|DELETE      |/magazines/:magazine_id/ads/:id      |destroy  |delete a specific ad belonging to a specific magazine                      |
251

252
This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+. These helpers take an instance of Magazine as the first parameter (+magazine_ads_url(@magazine)+).
253 254 255 256 257 258

h5. Limits to Nesting

You can nest resources within other nested resources if you like. For example:

<ruby>
259 260 261
resources :publishers do
  resources :magazines do
    resources :photos
262 263 264 265
  end
end
</ruby>

266
Deeply-nested resources quickly become cumbersome. In this case, for example, the application would recognize paths such as
267 268 269 270 271 272 273

<pre>
/publishers/1/magazines/2/photos/3
</pre>

The corresponding route helper would be +publisher_magazine_photo_url+, requiring you to specify objects at all three levels. Indeed, this situation is confusing enough that a popular "article":http://weblog.jamisbuck.org/2007/2/5/nesting-resources by Jamis Buck proposes a rule of thumb for good Rails design:

274
TIP: _Resources should never be nested more than 1 level deep._
275

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
h4. Routing concerns

Routing Concerns allows you to declare common routes that can be reused inside others resources and routes.

<ruby>
concern :commentable do
  resources :comments
end

concern :image_attachable do
  resources :images, only: :index
end
</ruby>

These concerns can be used in resources to avoid code duplication and share behavior across routes.

<ruby>
resources :messages, concerns: :commentable

resources :posts, concerns: [:commentable, :image_attachable]
</ruby>

Also you can use them in any place that you want inside the routes, for example in a scope or namespace call:

<ruby>
namespace :posts do
  concerns :commentable
end
</ruby>

306
h4. Creating Paths and URLs From Objects
307

308
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:
309 310

<ruby>
311 312
resources :magazines do
  resources :ads
313 314 315
end
</ruby>

316
When using +magazine_ad_path+, you can pass in instances of +Magazine+ and +Ad+ instead of the numeric IDs.
317

318
<erb>
319
<%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %>
320
</erb>
321

322
You can also use +url_for+ with a set of objects, and Rails will automatically determine which route you want:
323

324
<erb>
325
<%= link_to "Ad details", url_for([@magazine, @ad]) %>
326
</erb>
327

328
In this case, Rails will see that +@magazine+ is a +Magazine+ and +@ad+ is an +Ad+ and will therefore use the +magazine_ad_path+ helper. In helpers like +link_to+, you can specify just the object in place of the full +url_for+ call:
329

330 331 332
<erb>
<%= link_to "Ad details", [@magazine, @ad] %>
</erb>
333

V
Vijay Dev 已提交
334
If you wanted to link to just a magazine:
335

336 337 338
<erb>
<%= link_to "Magazine details", @magazine %>
</erb>
339

V
Vijay Dev 已提交
340
For other actions, you just need to insert the action name as the first element of the array:
341 342 343 344 345

<erb>
<%= link_to "Edit Ad", [:edit, @magazine, @ad] %>
</erb>

346
This allows you to treat instances of your models as URLs, and is a key advantage to using the resourceful style.
347 348 349

h4. Adding More RESTful Actions

350
You are not limited to the seven routes that RESTful routing creates by default. If you like, you may add additional routes that apply to the collection or individual members of the collection.
351 352 353

h5. Adding Member Routes

354
To add a member route, just add a +member+ block into the resource block:
355 356

<ruby>
357 358
resources :photos do
  member do
359
    get 'preview'
360 361
  end
end
362 363
</ruby>

364
This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers.
365

366
Within the block of member routes, each route name specifies the HTTP verb that it will recognize. 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:
367 368

<ruby>
369
resources :photos do
370
  get 'preview', :on => :member
371
end
372 373 374 375
</ruby>

h5. Adding Collection Routes

376
To add a route to the collection:
377 378

<ruby>
379 380
resources :photos do
  collection do
381
    get 'search'
382 383
  end
end
384 385
</ruby>

386
This will enable Rails to recognize paths such as +/photos/search+ with GET, and route to the +search+ action of +PhotosController+. It will also create the +search_photos_url+ and +search_photos_path+ route helpers.
387

388
Just as with member routes, you can pass +:on+ to a route:
389 390

<ruby>
391
resources :photos do
392
  get 'search', :on => :collection
393
end
394 395 396 397
</ruby>

h5. A Note of Caution

398
If you find yourself adding many extra actions to a resourceful route, it's time to stop and ask yourself whether you're disguising the presence of another resource.
399

400
h3. Non-Resourceful Routes
401

402
In addition to resource routing, Rails has powerful support for routing arbitrary URLs to actions. Here, you don't get groups of routes automatically generated by resourceful routing. Instead, you set up each route within your application separately.
403

404 405 406
While you should usually use resourceful routing, there are still many places where the simpler routing is more appropriate. There's no need to try to shoehorn every last piece of your application into a resourceful framework if that's not a good fit.

In particular, simple routing makes it very easy to map legacy URLs to new Rails actions.
407 408 409 410 411 412

h4. Bound Parameters

When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: +:controller+ maps to the name of a controller in your application, and +:action+ maps to the name of an action within that controller. For example, consider one of the default Rails routes:

<ruby>
413
get ':controller(/:action(/:id))'
414 415
</ruby>

E
eparreno 已提交
416
If an incoming request of +/photos/show/1+ is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the +show+ action of the +PhotosController+, and to make the final parameter +"1"+ available as +params[:id]+. This route will also route the incoming request of +/photos+ to +PhotosController#index+, since +:action+ and +:id+ are optional parameters, denoted by parentheses.
417

418
h4. Dynamic Segments
419

420
You can set up as many dynamic segments within a regular route as you like. Anything other than +:controller+ or +:action+ will be available to the action as part of +params+. If you set up this route:
421 422

<ruby>
423
get ':controller/:action/:id/:user_id'
424 425
</ruby>

426
An incoming path of +/photos/show/1/2+ will be dispatched to the +show+ action of the +PhotosController+. +params[:id]+ will be +"1"+, and +params[:user_id]+ will be +"2"+.
427

428
NOTE: You can't use +:namespace+ or +:module+ with a +:controller+ path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:
429 430

<ruby>
431
get ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/
432 433
</ruby>

434
TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, +:id+ => /[^\/]+/ allows anything except a slash.
435

436
h4. Static Segments
437

438
You can specify static segments when creating a route:
439 440

<ruby>
441
get ':controller/:action/:id/with_user/:user_id'
442 443
</ruby>

444
This route would respond to paths such as +/photos/show/1/with_user/2+. In this case, +params+ would be <tt>{ :controller => "photos", :action => "show", :id => "1", :user_id => "2" }</tt>.
445

446
h4. The Query String
447

448
The +params+ will also include any parameters from the query string. For example, with this route:
449 450

<ruby>
451
get ':controller/:action/:id'
452 453
</ruby>

454
An incoming path of +/photos/show/1?user_id=2+ will be dispatched to the +show+ action of the +Photos+ controller. +params+ will be <tt>{ :controller => "photos", :action => "show", :id => "1", :user_id => "2" }</tt>.
455 456 457

h4. Defining Defaults

458
You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply them as defaults:
459 460

<ruby>
461
get 'photos/:id' => 'photos#show'
462 463
</ruby>

464
With this route, Rails will match an incoming path of +/photos/12+ to the +show+ action of +PhotosController+.
465

466
You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that you do not specify as dynamic segments. For example:
467 468

<ruby>
469
get 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' }
470 471
</ruby>

472
Rails would match +photos/12+ to the +show+ action of +PhotosController+, and set +params[:format]+ to +"jpg"+.
473

474
h4. Naming Routes
475

476
You can specify a name for any route using the +:as+ option.
477 478

<ruby>
479
get 'exit' => 'sessions#destroy', :as => :logout
480 481
</ruby>

E
eparreno 已提交
482
This will create +logout_path+ and +logout_url+ as named helpers in your application. Calling +logout_path+ will return +/exit+
483

484 485 486 487 488 489 490 491
You can also use this to override routing methods defined by resources, like this:

<ruby>
get ':username', :to => "users#show", :as => :user
</ruby>

This will define a +user_path+ method that will be available in controllers, helpers and views that will go to a route such as +/bob+. Inside the +show+ action of +UsersController+, +params[:username]+ will contain the username for the user. Change +:username+ in the route definition if you do not want your parameter name to be +:username+.

492 493
h4. HTTP Verb Constraints

494
In general, you should use the +get+, +post+, +put+ 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:
495 496

<ruby>
497
match 'photos' => 'photos#show', :via => [:get, :post]
498 499
</ruby>

500
You can match all verbs to a particular route using +:via => :all+:
501 502

<ruby>
503
match 'photos' => 'photos#show', :via => :all
504 505
</ruby>

506
You should avoid routing all verbs to an action unless you have a good reason to, as routing both +GET+ requests and +POST+ requests to a single action has security implications.
507

508
h4. Segment Constraints
509

510
You can use the +:constraints+ option to enforce a format for a dynamic segment:
511 512

<ruby>
513
get 'photos/:id' => 'photos#show', :constraints => { :id => /[A-Z]\d{5}/ }
514 515
</ruby>

516
This route would match paths such as +/photos/A12345+. You can more succinctly express the same route this way:
517 518

<ruby>
519
get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/
520 521
</ruby>

522
+:constraints+ takes regular expressions with the restriction that regexp anchors can't be used. For example, the following route will not work:
523 524

<ruby>
525
get '/:id' => 'posts#show', :constraints => {:id => /^\d/}
526 527 528 529 530 531 532
</ruby>

However, note that you don't need to use anchors because all routes are anchored at the start.

For example, the following routes would allow for +posts+ with +to_param+ values like +1-hello-world+ that always begin with a number and +users+ with +to_param+ values like +david+ that never begin with a number to share the root namespace:

<ruby>
533 534
get '/:id' => 'posts#show', :constraints => { :id => /\d.+/ }
get '/:username' => 'users#show'
535 536
</ruby>

537 538 539 540 541 542 543
h4. Request-Based Constraints

You can also constrain a route based on any method on the <a href="action_controller_overview.html#the-request-object">Request</a> object that returns a +String+.

You specify a request-based constraint the same way that you specify a segment constraint:

<ruby>
544
get "photos", :constraints => {:subdomain => "admin"}
545 546
</ruby>

V
Vijay Dev 已提交
547
You can also specify constraints in a block form:
548 549

<ruby>
550
namespace :admin do
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
  constraints :subdomain => "admin" do
    resources :photos
  end
end
</ruby>

h4. 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 blacklist to the +BlacklistController+. You could do:

<ruby>
class BlacklistConstraint
  def initialize
    @ips = Blacklist.retrieve_ips
  end

  def matches?(request)
    @ips.include?(request.remote_ip)
  end
end

TwitterClone::Application.routes.draw do
573
  get "*path" => "blacklist#index",
574 575 576 577
    :constraints => BlacklistConstraint.new
end
</ruby>

578 579 580 581
You can also specify constraints as a lambda:

<ruby>
TwitterClone::Application.routes.draw do
582
  get "*path" => "blacklist#index",
583 584 585 586
    :constraints => lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) }
end
</ruby>

V
Vijay Dev 已提交
587
Both the +matches?+ method and the lambda gets the +request+ object as an argument.
588

589 590 591 592 593
h4. Route Globbing

Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example

<ruby>
594
get 'photos/*other' => 'photos#unknown'
595 596
</ruby>

597
This route would match +photos/12+ or +/photos/long/path/to/12+, setting +params[:other]+ to +"12"+ or +"long/path/to/12"+.
598

599
Wildcard segments can occur anywhere in a route. For example,
600 601

<ruby>
602
get 'books/*section/:title' => 'books#show'
603 604 605 606
</ruby>

would match +books/some/section/last-words-a-memoir+ with +params[:section]+ equals +"some/section"+, and +params[:title]+ equals +"last-words-a-memoir"+.

607
Technically a route can have even more than one wildcard segment. The matcher assigns segments to parameters in an intuitive way. For example,
608 609

<ruby>
610
get '*a/foo/*b' => 'test#index'
611 612 613 614
</ruby>

would match +zoo/woo/foo/bar/baz+ with +params[:a]+ equals +"zoo/woo"+, and +params[:b]+ equals +"bar/baz"+.

615
NOTE: Starting from Rails 3.1, wildcard routes will always match the optional format segment by default. For example if you have this route:
616 617

<ruby>
618
get '*pages' => 'pages#show'
619 620 621 622 623
</ruby>

NOTE: By requesting +"/foo/bar.json"+, your +params[:pages]+ will be equals to +"foo/bar"+ with the request format of JSON. If you want the old 3.0.x behavior back, you could supply +:format => false+ like this:

<ruby>
624
get '*pages' => 'pages#show', :format => false
625 626
</ruby>

627 628 629
NOTE: If you want to make the format segment mandatory, so it cannot be omitted, you can supply +:format => true+ like this:

<ruby>
630
get '*pages' => 'pages#show', :format => true
631 632
</ruby>

633 634 635 636 637
h4. Redirection

You can redirect any path to another path using the +redirect+ helper in your router:

<ruby>
638
get "/stories" => redirect("/posts")
639 640 641 642 643
</ruby>

You can also reuse dynamic segments from the match in the path to redirect to:

<ruby>
644
get "/stories/:name" => redirect("/posts/%{name}")
645 646 647
</ruby>

You can also provide a block to redirect, which receives the params and (optionally) the request object:
648

649
<ruby>
650 651
get "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}" }
get "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" }
652 653
</ruby>

654
Please note that this redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible.
655

656
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.
657

658
h4. Routing to Rack Applications
659

660
Instead of a String, like +"posts#index"+, which corresponds to the +index+ action in the +PostsController+, you can specify any <a href="rails_on_rack.html">Rack application</a> as the endpoint for a matcher.
661 662

<ruby>
663
match "/application.js" => Sprockets, :via => :all
664 665
</ruby>

666
As long as +Sprockets+ responds to +call+ and returns a <tt>[status, headers, body]</tt>, the router won't know the difference between the Rack application and an action. This is an appropriate use of +:via => :all+, as you will want to allow your Rack application to handle all verbs as it considers appropriate.
667 668 669 670 671 672

NOTE: For the curious, +"posts#index"+ actually expands out to +PostsController.action(:index)+, which returns a valid Rack application.

h4. Using +root+

You can specify what Rails should route +"/"+ to with the +root+ method:
673 674

<ruby>
675
root :to => 'pages#main'
676
root 'pages#main' # shortcut for the above
677 678
</ruby>

679
You should put the +root+ route at the top of the file, because it is the most popular route and should be matched first. You also need to delete the +public/index.html+ file for the root route to take effect.
680

681 682
NOTE: The +root+ route only routes +GET+ requests to the action.

683 684 685 686 687 688 689 690
h4. Unicode character routes

You can specify unicode character routes directly. For example

<ruby>
match 'こんにちは' => 'welcome#index'
</ruby>

691 692 693 694 695 696 697 698 699 700 701 702
h3. Customizing Resourceful Routes

While the default routes and helpers generated by +resources :posts+ 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.

h4. Specifying a Controller to Use

The +:controller+ option lets you explicitly specify a controller to use for the resource. For example:

<ruby>
resources :photos, :controller => "images"
</ruby>

703
will recognize incoming paths beginning with +/photos+ but route to the +Images+ controller:
704

705 706 707 708 709 710
|_.HTTP Verb |_.Path           |_.action |_.named helper        |
|GET         |/photos          |index    | photos_path          |
|GET         |/photos/new      |new      | new_photo_path       |
|POST        |/photos          |create   | photos_path          |
|GET         |/photos/:id      |show     | photo_path(:id)      |
|GET         |/photos/:id/edit |edit     | edit_photo_path(:id) |
711
|PATCH/PUT   |/photos/:id      |update   | photo_path(:id)      |
712
|DELETE      |/photos/:id      |destroy  | photo_path(:id)      |
713

714
NOTE: Use +photos_path+, +new_photo_path+, etc. to generate paths for this resource.
715 716 717 718 719 720

h4. Specifying Constraints

You can use the +:constraints+ option to specify a required format on the implicit +id+. For example:

<ruby>
721
resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/}
722 723
</ruby>

R
Ryan Sandridge 已提交
724
This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, the router would no longer match +/photos/1+ to this route. Instead, +/photos/RR27+ would match.
725

726
You can specify a single constraint to apply to a number of routes by using the block form:
727 728

<ruby>
729
constraints(:id => /[A-Z][A-Z][0-9]+/) do
730 731 732 733 734
  resources :photos
  resources :accounts
end
</ruby>

735
NOTE: Of course, you can use the more advanced constraints available in non-resourceful routes in this context.
736

737
TIP: By default the +:id+ parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an +:id+ add a constraint which overrides this - for example +:id+ => /[^\/]+/ allows anything except a slash.
738

739 740 741 742 743 744 745 746
h4. Overriding the Named Helpers

The +:as+ option lets you override the normal naming for the named route helpers. For example:

<ruby>
resources :photos, :as => "images"
</ruby>

747
will recognize incoming paths beginning with +/photos+ and route the requests to +PhotosController+, but use the value of the :as option to name the helpers.
748

749 750 751 752 753 754
|_.HTTP verb|_.Path            |_.action |_.named helper        |
|GET        |/photos           |index    | images_path          |
|GET        |/photos/new       |new      | new_image_path       |
|POST       |/photos           |create   | images_path          |
|GET        |/photos/:id       |show     | image_path(:id)      |
|GET        |/photos/:id/edit  |edit     | edit_image_path(:id) |
755
|PATCH/PUT  |/photos/:id       |update   | image_path(:id)      |
756
|DELETE     |/photos/:id       |destroy  | image_path(:id)      |
757 758 759

h4. Overriding the +new+ and +edit+ Segments

760
The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in paths:
761 762 763 764 765

<ruby>
resources :photos, :path_names => { :new => 'make', :edit => 'change' }
</ruby>

766
This would cause the routing to recognize paths such as
767

W
wycats 已提交
768
<plain>
769 770
/photos/make
/photos/1/change
W
wycats 已提交
771
</plain>
772

773
NOTE: The actual action names aren't changed by this option. The two paths shown would still route to the +new+ and +edit+ actions.
774

775
TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can use a scope.
776 777 778 779

<ruby>
scope :path_names => { :new => "make" } do
  # rest of your routes
780 781 782
end
</ruby>

783
h4. Prefixing the Named Route Helpers
784

785
You can use the +:as+ option to prefix the named route helpers that Rails generates for a route. Use this option to prevent name collisions between routes using a path scope.
786

787 788
<ruby>
scope "admin" do
789
  resources :photos, :as => "admin_photos"
790
end
791

792 793 794
resources :photos
</ruby>

795
This will provide route helpers such as +admin_photos_path+, +new_admin_photo_path+ etc.
796

797
To prefix a group of route helpers, use +:as+ with +scope+:
798 799

<ruby>
800
scope "admin", :as => "admin" do
801 802 803 804
  resources :photos, :accounts
end

resources :photos, :accounts
805 806
</ruby>

807
This will generate routes such as +admin_photos_path+ and +admin_accounts_path+ which map to +/admin/photos+ and +/admin/accounts+ respectively.
808

809
NOTE: The +namespace+ scope will automatically add +:as+ as well as +:module+ and +:path+ prefixes.
810

811 812 813 814 815 816 817 818 819 820
You can prefix routes with a named parameter also:

<ruby>
scope ":username" do
  resources :posts
end
</ruby>

This will provide you with URLs such as +/bob/posts/1+ and will allow you to reference the +username+ part of the path as +params[:username]+ in controllers, helpers and views.

821
h4. Restricting the Routes Created
822

823
By default, Rails creates routes for the seven default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the +:only+ and +:except+ options to fine-tune this behavior. The +:only+ option tells Rails to create only the specified routes:
824 825

<ruby>
826
resources :photos, :only => [:index, :show]
827 828
</ruby>

829 830 831
Now, a +GET+ request to +/photos+ would succeed, but a +POST+ request to +/photos+ (which would ordinarily be routed to the +create+ action) will fail.

The +:except+ option specifies a route or list of routes that Rails should _not_ create:
832

833 834 835
<ruby>
resources :photos, :except => :destroy
</ruby>
836

837
In this case, Rails will create all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/:id+).
838

839
TIP: If your application has many RESTful routes, using +:only+ and +:except+ to generate only the routes that you actually need can cut down on memory use and speed up the routing process.
840

841
h4. Translated Paths
842

843
Using +scope+, we can alter path names generated by resources:
844 845

<ruby>
846 847 848
scope(:path_names => { :new => "neu", :edit => "bearbeiten" }) do
  resources :categories, :path => "kategorien"
end
849 850
</ruby>

851
Rails now creates routes to the +CategoriesController+.
852

853 854 855 856 857 858
|_.HTTP verb|_.Path                     |_.action |_.named helper           |
|GET        |/kategorien                |index    | categories_path         |
|GET        |/kategorien/neu            |new      | new_category_path       |
|POST       |/kategorien                |create   | categories_path         |
|GET        |/kategorien/:id            |show     | category_path(:id)      |
|GET        |/kategorien/:id/bearbeiten |edit     | edit_category_path(:id) |
859
|PATCH/PUT  |/kategorien/:id            |update   | category_path(:id)      |
860
|DELETE     |/kategorien/:id            |destroy  | category_path(:id)      |
861

862
h4. Overriding the Singular Form
863

864
If you want to define the singular form of a resource, you should add additional rules to the +Inflector+.
865 866

<ruby>
867 868 869
ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'tooth', 'teeth'
end
870 871
</ruby>

872
h4(#nested-names). Using +:as+ in Nested Resources
873

874
The +:as+ option overrides the automatically-generated name for the resource in nested route helpers. For example,
875 876 877

<ruby>
resources :magazines do
878
  resources :ads, :as => 'periodical_ads'
879
end
880 881
</ruby>

882
This will create routing helpers such as +magazine_periodical_ads_url+ and +edit_magazine_periodical_ad_path+.
883 884 885

h3. Inspecting and Testing Routes

886
Rails offers facilities for inspecting and testing your routes.
887

888
h4. Seeing Existing Routes
889

V
Vijay Dev 已提交
890 891 892
To get a complete list of the available routes in your application, visit +http://localhost:3000/rails/info/routes+ in your browser while your server is running in the *development* environment. You can also execute the +rake routes+ command in your terminal to produce the same output.

Both methods will list all of your routes, in the same order that they appear in +routes.rb+. For each route, you'll see:
893 894 895

* The route name (if any)
* The HTTP verb used (if the route doesn't respond to all verbs)
896 897
* The URL pattern to match
* The routing parameters for the route
898 899 900 901

For example, here's a small section of the +rake routes+ output for a RESTful route:

<pre>
902 903 904 905
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
906 907
</pre>

908 909 910
You may restrict the listing to the routes that map to a particular controller setting the +CONTROLLER+ environment variable:

<shell>
911
$ CONTROLLER=users rake routes
912 913
</shell>

914 915 916 917
TIP: You'll find that the output from +rake routes+ is much more readable if you widen your terminal window until the output lines don't wrap.

h4. Testing Routes

918
Routes should be included in your testing strategy (just like the rest of your application). Rails offers three "built-in assertions":http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html designed to make testing routes simpler:
919 920 921 922 923 924 925

* +assert_generates+
* +assert_recognizes+
* +assert_routing+

h5. The +assert_generates+ Assertion

926
+assert_generates+ asserts that a particular set of options generate a particular path and can be used with default routes or custom routes.
927 928 929 930 931 932 933 934

<ruby>
assert_generates "/photos/1", { :controller => "photos", :action => "show", :id => "1" }
assert_generates "/about", :controller => "pages", :action => "about"
</ruby>

h5. The +assert_recognizes+ Assertion

935
+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.
936 937

<ruby>
938
assert_recognizes({ :controller => "photos", :action => "show", :id => "1" }, "/photos/1")
939 940 941 942 943
</ruby>

You can supply a +:method+ argument to specify the HTTP verb:

<ruby>
944
assert_recognizes({ :controller => "photos", :action => "create" }, { :path => "photos", :method => :post })
945 946 947 948 949 950 951
</ruby>

h5. 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+.

<ruby>
952
assert_routing({ :path => "photos", :method => :post }, { :controller => "photos", :action => "create" })
953
</ruby>