~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/railties/guides/source/routing.textile

  • Committer: Richard Lee (Canonical)
  • Date: 2010-10-15 15:17:58 UTC
  • mfrom: (190.1.3 use-case-mapper)
  • Revision ID: richard.lee@canonical.com-20101015151758-wcvmfxrexsongf9d
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
h2. Rails Routing from the Outside In
2
 
 
3
 
This guide covers the user-facing features of Rails routing. By referring to this guide, you will be able to:
4
 
 
5
 
* Understand the purpose of routing
6
 
* Decipher the code in +routes.rb+
7
 
* Construct your own routes, using either the classic hash style or the now-preferred RESTful style
8
 
* Identify how a route will map to a controller and action
9
 
 
10
 
endprologue.
11
 
 
12
 
h3. The Dual Purpose of Routing
13
 
 
14
 
Rails routing is a two-way piece of machinery - rather as if you could turn trees into paper, and then turn paper back into trees. Specifically, it both connects incoming HTTP requests to the code in your application's controllers, and helps you generate URLs without having to hard-code them as strings.
15
 
 
16
 
h4. Connecting URLs to Code
17
 
 
18
 
When your Rails application receives an incoming HTTP request, say
19
 
 
20
 
<pre>
21
 
GET /patients/17
22
 
</pre>
23
 
 
24
 
the routing engine within Rails is the piece of code that dispatches the request to the appropriate spot in your application. In this case, the application would most likely end up running the +show+ action within the +patients+ controller, displaying the details of the patient whose ID is 17.
25
 
 
26
 
h4. Generating URLs from Code
27
 
 
28
 
Routing also works in reverse. If your application contains this code:
29
 
 
30
 
<ruby>
31
 
@patient = Patient.find(17)
32
 
</ruby>
33
 
 
34
 
<erb>
35
 
<%= link_to "Patient Record", patient_path(@patient) %>
36
 
</erb>
37
 
 
38
 
Then the routing engine is the piece that translates that to a link to a URL such as +http://example.com/patients/17+. By using routing in this way, you can reduce the brittleness of your application as compared to one with hard-coded URLs, and make your code easier to read and understand.
39
 
 
40
 
NOTE: Patient needs to be declared as a resource for this style of translation via a named route to be available.
41
 
 
42
 
h3. Quick Tour of +routes.rb+
43
 
 
44
 
There are two components to routing in Rails: the routing engine itself, which is supplied as part of Rails, and the file +config/routes.rb+, which contains the actual routes that will be used by your application. Learning exactly what you can put in +routes.rb+ is the main topic of this guide, but before we dig in let's get a quick overview.
45
 
 
46
 
h4. Processing the File
47
 
 
48
 
In format, +routes.rb+ is nothing more than one big block sent to +ActionController::Routing::Routes.draw+. Within this block, you can have comments, but it's likely that most of your content will be individual lines of code - each line being a route in your application. You'll find five main types of content in this file:
49
 
 
50
 
* RESTful Routes
51
 
* Named Routes
52
 
* Nested Routes
53
 
* Regular Routes
54
 
* Default Routes
55
 
 
56
 
Each of these types of route is covered in more detail later in this guide.
57
 
 
58
 
The +routes.rb+ file is processed from top to bottom when a request comes in. The request will be dispatched to the first matching route. If there is no matching route, then Rails returns HTTP status 404 to the caller.
59
 
 
60
 
h4. RESTful Routes
61
 
 
62
 
RESTful routes take advantage of the built-in REST orientation of Rails to wrap up a lot of routing information in a single declaration. A RESTful route looks like this:
63
 
 
64
 
<ruby>
65
 
map.resources :books
66
 
</ruby>
67
 
 
68
 
h4. Named Routes
69
 
 
70
 
Named routes give you very readable links in your code, as well as handling incoming requests. Here's a typical named route:
71
 
 
72
 
<ruby>
73
 
map.login '/login', :controller => 'sessions', :action => 'new'
74
 
</ruby>
75
 
 
76
 
h4. Nested Routes
77
 
 
78
 
Nested routes let you declare that one resource is contained within another resource. You'll see later on how this translates to URLs and paths in your code. For example, if your application includes parts, each of which belongs to an assembly, you might have this nested route declaration:
79
 
 
80
 
<ruby>
81
 
map.resources :assemblies do |assemblies|
82
 
  assemblies.resources :parts
83
 
end
84
 
</ruby>
85
 
 
86
 
h4. Regular Routes
87
 
 
88
 
In many applications, you'll also see non-RESTful routing, which explicitly connects the parts of a URL to a particular action. For example,
89
 
 
90
 
<ruby>
91
 
map.connect 'parts/:number', :controller => 'inventory', :action => 'show'
92
 
</ruby>
93
 
 
94
 
h4. Default Routes
95
 
 
96
 
The default routes are a safety net that catch otherwise-unrouted requests. Many Rails applications will contain this pair of default routes:
97
 
 
98
 
<ruby>
99
 
map.connect ':controller/:action/:id'
100
 
map.connect ':controller/:action/:id.:format'
101
 
</ruby>
102
 
 
103
 
These default routes are automatically generated when you create a new Rails application. If you're using RESTful routing for everything in your application, you will probably want to remove them. But be sure you're not using the default routes before you remove them!
104
 
 
105
 
h3. RESTful Routing: the Rails Default
106
 
 
107
 
RESTful routing is the current standard for routing in Rails, and it's the one that you should prefer for new applications. It can take a little while to understand how RESTful routing works, but it's worth the effort; your code will be easier to read and you'll be working with Rails, rather than fighting against it, when you use this style of routing.
108
 
 
109
 
h4. What is REST?
110
 
 
111
 
The foundation of RESTful routing is generally considered to be Roy Fielding's doctoral thesis, "Architectural Styles and the Design of Network-based Software Architectures":http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm. Fortunately, you need not read this entire document to understand how REST works in Rails. REST, an acronym for Representational State Transfer, boils down to two main principles for our purposes:
112
 
 
113
 
* Using resource identifiers (which, for the purposes of discussion, you can think of as URLs) to represent resources
114
 
* Transferring representations of the state of that resource between system components.
115
 
 
116
 
For example, to a Rails application a request such as this:
117
 
 
118
 
<pre>
119
 
DELETE /photos/17
120
 
</pre>
121
 
 
122
 
would be understood to refer to a photo resource with the ID of 17, and to indicate a desired action - deleting that resource. REST is a natural style for the architecture of web applications, and Rails makes it even more natural by using conventions to shield you from some of the RESTful complexities.
123
 
 
124
 
h4. CRUD, Verbs, and Actions
125
 
 
126
 
In Rails, a RESTful route provides a mapping between HTTP verbs, controller actions, and (implicitly) CRUD operations in a database. A single entry in the routing file, such as
127
 
 
128
 
<ruby>
129
 
map.resources :photos
130
 
</ruby>
131
 
 
132
 
creates seven different routes in your application:
133
 
 
134
 
|_.HTTP verb|_.URL           |_.controller|_.action |_.used for|
135
 
|GET        |/photos         |Photos      |index    |display a list of all photos|
136
 
|GET        |/photos/new     |Photos      |new      |return an HTML form for creating a new photo|
137
 
|POST       |/photos         |Photos      |create   |create a new photo|
138
 
|GET        |/photos/1       |Photos      |show     |display a specific photo|
139
 
|GET        |/photos/1/edit  |Photos      |edit     |return an HTML form for editing a photo|
140
 
|PUT        |/photos/1       |Photos      |update   |update a specific photo|
141
 
|DELETE     |/photos/1       |Photos      |destroy  |delete a specific photo|
142
 
 
143
 
For the specific routes (those that reference just a single resource), the identifier for the resource will be available within the corresponding controller action as +params[:id]+.
144
 
 
145
 
TIP: If you consistently use RESTful routes in your application, you should disable the default routes in +routes.rb+ so that Rails will enforce the mapping between HTTP verbs and routes.
146
 
 
147
 
h4. URLs and Paths
148
 
 
149
 
Creating a RESTful route will also make available a pile of helpers within your application:
150
 
 
151
 
* +photos_url+ and +photos_path+ map to the path for the index and create actions
152
 
* +new_photo_url+ and +new_photo_path+ map to the path for the new action
153
 
* +edit_photo_url+ and +edit_photo_path+ map to the path for the edit action
154
 
* +photo_url+ and +photo_path+ map to the path for the show, update, and destroy actions
155
 
 
156
 
NOTE: Because routing makes use of the HTTP verb as well as the path in the request to dispatch requests, the seven routes generated by a RESTful routing entry only give rise to four pairs of helpers.
157
 
 
158
 
In each case, the +_url+ helper generates a string containing the entire URL that the application will understand, while the +_path+ helper generates a string containing the relative path from the root of the application. For example:
159
 
 
160
 
<ruby>
161
 
photos_url  # => "http://www.example.com/photos"
162
 
photos_path # => "/photos"
163
 
</ruby>
164
 
 
165
 
h4. Defining Multiple Resources at the Same Time
166
 
 
167
 
If you need to create routes for more than one RESTful resource, you can save a bit of typing by defining them all with a single call to +map.resources+:
168
 
 
169
 
<ruby>
170
 
map.resources :photos, :books, :videos
171
 
</ruby>
172
 
 
173
 
This has exactly the same effect as
174
 
 
175
 
<ruby>
176
 
map.resources :photos
177
 
map.resources :books
178
 
map.resources :videos
179
 
</ruby>
180
 
 
181
 
h4. Singular Resources
182
 
 
183
 
You can also apply RESTful routing to singleton resources within your application. In this case, you use +map.resource+ instead of +map.resources+ and the route generation is slightly different. For example, a routing entry of
184
 
 
185
 
<ruby>
186
 
map.resource :geocoder
187
 
</ruby>
188
 
 
189
 
creates six different routes in your application:
190
 
 
191
 
|_.HTTP verb|_.URL           |_.controller|_.action |_.used for|
192
 
|GET        |/geocoder/new   |Geocoders   |new      |return an HTML form for creating the new geocoder|
193
 
|POST       |/geocoder       |Geocoders   |create   |create the new geocoder|
194
 
|GET        |/geocoder       |Geocoders   |show     |display the one and only geocoder resource|
195
 
|GET        |/geocoder/edit  |Geocoders   |edit     |return an HTML form for editing the geocoder|
196
 
|PUT        |/geocoder       |Geocoders   |update   |update the one and only geocoder resource|
197
 
|DELETE     |/geocoder       |Geocoders   |destroy  |delete the geocoder resource|
198
 
 
199
 
NOTE: Even though the name of the resource is singular in +routes.rb+, the matching controller is still plural.
200
 
 
201
 
A singular RESTful route generates an abbreviated set of helpers:
202
 
 
203
 
* +new_geocoder_url+ and +new_geocoder_path+ map to the path for the new action
204
 
* +edit_geocoder_url+ and +edit_geocoder_path+ map to the path for the edit action
205
 
* +geocoder_url+ and +geocoder_path+ map to the path for the create, show, update, and destroy actions
206
 
 
207
 
h4. Customizing Resources
208
 
 
209
 
Although the conventions of RESTful routing are likely to be sufficient for many applications, there are a number of ways to customize the way that RESTful routes work. These options include:
210
 
 
211
 
* +:controller+
212
 
* +:singular+
213
 
* +:requirements+
214
 
* +:conditions+
215
 
* +:as+
216
 
* +:path_names+
217
 
* +:path_prefix+
218
 
* +:name_prefix+
219
 
* +:only+
220
 
* +:except+
221
 
 
222
 
You can also add additional routes via the +:member+ and +:collection+ options, which are discussed later in this guide.
223
 
 
224
 
h5. Using +:controller+
225
 
 
226
 
The +:controller+ option lets you use a controller name that is different from the public-facing resource name. For example, this routing entry:
227
 
 
228
 
<ruby>
229
 
map.resources :photos, :controller => "images"
230
 
</ruby>
231
 
 
232
 
will recognize incoming URLs containing +photo+ but route the requests to the Images controller:
233
 
 
234
 
|_.HTTP verb|_.URL           |_.controller|_.action |_.used for|
235
 
|GET        |/photos         |Images      |index    |display a list of all images|
236
 
|GET        |/photos/new     |Images      |new      |return an HTML form for creating a new image|
237
 
|POST       |/photos         |Images      |create   |create a new image|
238
 
|GET        |/photos/1       |Images      |show     |display a specific image|
239
 
|GET        |/photos/1/edit  |Images      |edit     |return an HTML form for editing a image|
240
 
|PUT        |/photos/1       |Images      |update   |update a specific image|
241
 
|DELETE     |/photos/1       |Images      |destroy  |delete a specific image|
242
 
 
243
 
NOTE: The helpers will be generated with the name of the resource, not the name of the controller. So in this case, you'd still get +photos_path+, +new_photo_path+, and so on.
244
 
 
245
 
h4. Controller Namespaces and Routing
246
 
 
247
 
Rails allows you to group your controllers into namespaces by saving them in folders underneath +app/controllers+. The +:controller+ option provides a convenient way to use these routes. For example, you might have a resource whose controller is purely for admin users in the +admin+ folder:
248
 
 
249
 
<ruby>
250
 
map.resources :adminphotos, :controller => "admin/photos"
251
 
</ruby>
252
 
 
253
 
If you use controller namespaces, you need to be aware of a subtlety in the Rails routing code: it always tries to preserve as much of the namespace from the previous request as possible. For example, if you are on a view generated from the +adminphoto_path+ helper, and you follow a link generated with +&lt;%= link_to "show", adminphoto(1) %&gt;+ you will end up on the view generated by +admin/photos/show+, but you will also end up in the same place if you have +&lt;%= link_to "show", {:controller => "photos", :action => "show"} %&gt;+ because Rails will generate the show URL relative to the current URL.
254
 
 
255
 
TIP: If you want to guarantee that a link goes to a top-level controller, use a preceding slash to anchor the controller name: +&lt;%= link_to "show", {:controller => "/photos", :action => "show"} %&gt;+
256
 
 
257
 
You can also specify a controller namespace with the +:namespace+ option instead of a path:
258
 
 
259
 
<ruby>
260
 
map.resources :adminphotos, :namespace => "admin", :controller => "photos"
261
 
</ruby>
262
 
 
263
 
This can be especially useful when combined with +with_options+ to map multiple namespaced routes together:
264
 
 
265
 
<ruby>
266
 
map.with_options(:namespace => "admin") do |admin|
267
 
  admin.resources :photos, :videos
268
 
end
269
 
</ruby>
270
 
 
271
 
That would give you routing for +admin/photos+ and +admin/videos+ controllers.
272
 
 
273
 
h5. Using +:singular+
274
 
 
275
 
If for some reason Rails isn't doing what you want in converting the plural resource name to a singular name in member routes, you can override its judgment with the +:singular+ option:
276
 
 
277
 
<ruby>
278
 
map.resources :teeth, :singular => "tooth"
279
 
</ruby>
280
 
 
281
 
TIP: Depending on the other code in your application, you may prefer to add additional rules to the +Inflector+ class instead.
282
 
 
283
 
h5. Using +:requirements+
284
 
 
285
 
You can use the +:requirements+ option in a RESTful route to impose a format on the implied +:id+ parameter in the singular routes. For example:
286
 
 
287
 
<ruby>
288
 
map.resources :photos, :requirements => {:id => /[A-Z][A-Z][0-9]+/}
289
 
</ruby>
290
 
 
291
 
This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, +/photos/1+ would no longer be recognized by this route, but +/photos/RR27+ would.
292
 
 
293
 
h5. Using +:conditions+
294
 
 
295
 
Conditions in Rails routing are currently used only to set the HTTP verb for individual routes. Although in theory you can set this for RESTful routes, in practice there is no good reason to do so. (You'll learn more about conditions in the discussion of classic routing later in this guide.)
296
 
 
297
 
h5. Using +:as+
298
 
 
299
 
The +:as+ option lets you override the normal naming for the actual generated paths. For example:
300
 
 
301
 
<ruby>
302
 
map.resources :photos, :as => "images"
303
 
</ruby>
304
 
 
305
 
will recognize incoming URLs containing +image+ but route the requests to the Photos controller:
306
 
 
307
 
|_.HTTP verb|_.URL           |_.controller|_.action |_:used for|
308
 
|GET        |/images         |Photos      |index    |display a list of all photos|
309
 
|GET        |/images/new     |Photos      |new      |return an HTML form for creating a new photo|
310
 
|POST       |/images         |Photos      |create   |create a new photo|
311
 
|GET        |/images/1       |Photos      |show     |display a specific photo|
312
 
|GET        |/images/1/edit  |Photos      |edit     |return an HTML form for editing a photo|
313
 
|PUT        |/images/1       |Photos      |update   |update a specific photo|
314
 
|DELETE     |/images/1       |Photos      |destroy  |delete a specific photo|
315
 
 
316
 
NOTE: The helpers will be generated with the name of the resource, not the path name. So in this case, you'd still get +photos_path+, +new_photo_path+, and so on.
317
 
 
318
 
h5. Using +:path_names+
319
 
 
320
 
The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in URLs:
321
 
 
322
 
<ruby>
323
 
map.resources :photos, :path_names => { :new => 'make', :edit => 'change' }
324
 
</ruby>
325
 
 
326
 
This would cause the routing to recognize URLs such as
327
 
 
328
 
<pre>
329
 
/photos/make
330
 
/photos/1/change
331
 
</pre>
332
 
 
333
 
NOTE: The actual action names aren't changed by this option; the two URLs shown would still route to the new and edit actions.
334
 
 
335
 
TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can set a default in your environment:
336
 
 
337
 
<ruby>
338
 
config.action_controller.resources_path_names = { :new => 'make', :edit => 'change' }
339
 
</ruby>
340
 
 
341
 
h5. Using +:path_prefix+
342
 
 
343
 
The +:path_prefix+ option lets you add additional parameters that will be prefixed to the recognized paths. For example, suppose each photo in your application belongs to a particular photographer. In that case, you might declare this route:
344
 
 
345
 
<ruby>
346
 
map.resources :photos, :path_prefix => '/photographers/:photographer_id'
347
 
</ruby>
348
 
 
349
 
Routes recognized by this entry would include:
350
 
 
351
 
<pre>
352
 
/photographers/1/photos/2
353
 
/photographers/1/photos
354
 
</pre>
355
 
 
356
 
NOTE: In most cases, it's simpler to recognize URLs of this sort by creating nested resources, as discussed in the next section.
357
 
 
358
 
NOTE: You can also use +:path_prefix+ with non-RESTful routes.
359
 
 
360
 
h5. Using +:name_prefix+
361
 
 
362
 
You can use the :name_prefix option to avoid collisions between routes. This is most useful when you have two resources with the same name that use +:path_prefix+ to map differently. For example:
363
 
 
364
 
<ruby>
365
 
map.resources :photos, :path_prefix => '/photographers/:photographer_id',
366
 
  :name_prefix => 'photographer_'
367
 
map.resources :photos, :path_prefix => '/agencies/:agency_id',
368
 
  :name_prefix => 'agency_'
369
 
</ruby>
370
 
 
371
 
This combination will give you route helpers such as +photographer_photos_path+ and +agency_edit_photo_path+ to use in your code.
372
 
 
373
 
NOTE: You can also use +:name_prefix+ with non-RESTful routes.
374
 
 
375
 
h5. Using +:only+ and +:except+
376
 
 
377
 
By default, Rails creates routes for all seven of the 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 specifies that only certain routes should be generated:
378
 
 
379
 
<ruby>
380
 
map.resources :photos, :only => [:index, :show]
381
 
</ruby>
382
 
 
383
 
With this declaration, a +GET+ request to +/photos+ would succeed, but a +POST+ request to +/photos+ (which would ordinarily be routed to the create action) will fail.
384
 
 
385
 
The +:except+ option specifies a route or list of routes that should _not_ be generated:
386
 
 
387
 
<ruby>
388
 
map.resources :photos, :except => :destroy
389
 
</ruby>
390
 
 
391
 
In this case, all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/<em>id</em>+) will be generated.
392
 
 
393
 
In addition to an action or a list of actions, you can also supply the special symbols +:all+ or +:none+ to the +:only+ and +:except+ options.
394
 
 
395
 
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.
396
 
 
397
 
h4. Nested Resources
398
 
 
399
 
It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:
400
 
 
401
 
<ruby>
402
 
class Magazine < ActiveRecord::Base
403
 
  has_many :ads
404
 
end
405
 
 
406
 
class Ad < ActiveRecord::Base
407
 
  belongs_to :magazine
408
 
end
409
 
</ruby>
410
 
 
411
 
Each ad is logically subservient to one magazine. Nested routes allow you to capture this relationship in your routing. In this case, you might include this route declaration:
412
 
 
413
 
<ruby>
414
 
map.resources :magazines do |magazine|
415
 
  magazine.resources :ads
416
 
end
417
 
</ruby>
418
 
 
419
 
TIP: Further below you'll learn about a convenient shortcut for this construct:<br/>+map.resources :magazines, :has_many => :ads+.
420
 
 
421
 
In addition to the routes for magazines, this declaration will also create routes for ads, each of which requires the specification of a magazine in the URL:
422
 
 
423
 
|_.HTTP verb|_.URL                    |_.controller|_.action |_.used for|
424
 
|GET        |/magazines/1/ads         |Ads         |index    |display a list of all ads for a specific magazine|
425
 
|GET        |/magazines/1/ads/new     |Ads         |new      |return an HTML form for creating a new ad belonging to a specific magazine|
426
 
|POST       |/magazines/1/ads         |Ads         |create   |create a new ad belonging to a specific magazine|
427
 
|GET        |/magazines/1/ads/1       |Ads         |show     |display a specific ad belonging to a specific magazine|
428
 
|GET        |/magazines/1/ads/1/edit  |Ads         |edit     |return an HTML form for editing an ad belonging to a specific magazine|
429
 
|PUT        |/magazines/1/ads/1       |Ads         |update   |update a specific ad belonging to a specific magazine|
430
 
|DELETE     |/magazines/1/ads/1       |Ads         |destroy  |delete a specific ad belonging to a specific magazine|
431
 
 
432
 
 
433
 
This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+.
434
 
 
435
 
h5. Using +:name_prefix+
436
 
 
437
 
The +:name_prefix+ option overrides the automatically-generated prefix in nested route helpers. For example,
438
 
 
439
 
<ruby>
440
 
map.resources :magazines do |magazine|
441
 
  magazine.resources :ads, :name_prefix => 'periodical'
442
 
end
443
 
</ruby>
444
 
 
445
 
This will create routing helpers such as +periodical_ads_url+ and +periodical_edit_ad_path+. You can even use +:name_prefix+ to suppress the prefix entirely:
446
 
 
447
 
<ruby>
448
 
map.resources :magazines do |magazine|
449
 
  magazine.resources :ads, :name_prefix => nil
450
 
end
451
 
</ruby>
452
 
 
453
 
This will create routing helpers such as +ads_url+ and +edit_ad_path+. Note that calling these will still require supplying an article id:
454
 
 
455
 
<ruby>
456
 
ads_url(@magazine)
457
 
edit_ad_path(@magazine, @ad)
458
 
</ruby>
459
 
 
460
 
h5. Using +:has_one+ and +:has_many+
461
 
 
462
 
The +:has_one+ and +:has_many+ options provide a succinct notation for simple nested routes. Use +:has_one+ to nest a singleton resource, or +:has_many+ to nest a plural resource:
463
 
 
464
 
<ruby>
465
 
map.resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
466
 
</ruby>
467
 
 
468
 
This has the same effect as this set of declarations:
469
 
 
470
 
<ruby>
471
 
map.resources :photos do |photo|
472
 
  photo.resource :photographer
473
 
  photo.resources :publications
474
 
  photo.resources :versions
475
 
end
476
 
</ruby>
477
 
 
478
 
h5. Limits to Nesting
479
 
 
480
 
You can nest resources within other nested resources if you like. For example:
481
 
 
482
 
<ruby>
483
 
map.resources :publishers do |publisher|
484
 
  publisher.resources :magazines do |magazine|
485
 
    magazine.resources :photos
486
 
  end
487
 
end
488
 
</ruby>
489
 
 
490
 
However, without the use of +name_prefix => nil+, deeply-nested resources quickly become cumbersome. In this case, for example, the application would recognize URLs such as
491
 
 
492
 
<pre>
493
 
/publishers/1/magazines/2/photos/3
494
 
</pre>
495
 
 
496
 
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:
497
 
 
498
 
TIP: _Resources should never be nested more than 1 level deep._
499
 
 
500
 
h5. Shallow Nesting
501
 
 
502
 
The +:shallow+ option provides an elegant solution to the difficulties of deeply-nested routes. If you specify this option at any level of routing, then paths for nested resources which reference a specific member (that is, those with an +:id+ parameter) will not use the parent path prefix or name prefix. To see what this means, consider this set of routes:
503
 
 
504
 
<ruby>
505
 
map.resources :publishers, :shallow => true do |publisher|
506
 
  publisher.resources :magazines do |magazine|
507
 
    magazine.resources :photos
508
 
  end
509
 
end
510
 
</ruby>
511
 
 
512
 
This will enable recognition of (among others) these routes:
513
 
 
514
 
<pre>
515
 
/publishers/1           ==> publisher_path(1)
516
 
/publishers/1/magazines ==> publisher_magazines_path(1)
517
 
/magazines/2            ==> magazine_path(2)
518
 
/magazines/2/photos     ==> magazines_photos_path(2)
519
 
/photos/3               ==> photo_path(3)
520
 
</pre>
521
 
 
522
 
With shallow nesting, you need only supply enough information to uniquely identify the resource that you want to work with. If you like, you can combine shallow nesting with the +:has_one+ and +:has_many+ options:
523
 
 
524
 
<ruby>
525
 
map.resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
526
 
</ruby>
527
 
 
528
 
h4. Route Generation from Arrays
529
 
 
530
 
In addition to using the generated routing helpers, Rails can also generate RESTful routes from an array of parameters. For example, suppose you have a set of routes generated with these entries in routes.rb:
531
 
 
532
 
<ruby>
533
 
map.resources :magazines do |magazine|
534
 
  magazine.resources :ads
535
 
end
536
 
</ruby>
537
 
 
538
 
Rails will generate helpers such as magazine_ad_path that you can use in building links:
539
 
 
540
 
<ruby>
541
 
<%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %>
542
 
</ruby>
543
 
 
544
 
Another way to refer to the same route is with an array of objects:
545
 
 
546
 
<ruby>
547
 
<%= link_to "Ad details", [@magazine, @ad] %>
548
 
</ruby>
549
 
 
550
 
This format is especially useful when you might not know until runtime which of several types of object will be used in a particular link.
551
 
 
552
 
h4. Namespaced Resources
553
 
 
554
 
It's possible to do some quite complex things by combining +:path_prefix+ and +:name_prefix+. For example, you can use the combination of these two options to move administrative resources to their own folder in your application:
555
 
 
556
 
<ruby>
557
 
map.resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
558
 
map.resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
559
 
map.resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
560
 
</ruby>
561
 
 
562
 
The good news is that if you find yourself using this level of complexity, you can stop. Rails supports _namespaced resources_ to make placing resources in their own folder a snap. Here's the namespaced version of those same three routes:
563
 
 
564
 
<ruby>
565
 
map.namespace(:admin) do |admin|
566
 
        admin.resources :photos,
567
 
          :has_many => { :tags, :ratings}
568
 
end
569
 
</ruby>
570
 
 
571
 
As you can see, the namespaced version is much more succinct than the one that spells everything out - but it still creates the same routes. For example, you'll get +admin_photos_url+ that expects to find an +Admin::PhotosController+ and that matches +admin/photos+, and +admin_photos_ratings_path+ that matches +/admin/photos/_photo_id_/ratings+, expecting to use +Admin::RatingsController+. Even though you're not specifying +path_prefix+ explicitly, the routing code will calculate the appropriate +path_prefix+ from the route nesting.
572
 
 
573
 
h4. Adding More RESTful Actions
574
 
 
575
 
You are not limited to the seven routes that RESTful routing creates by default. If you like, you may add additional member routes (those which apply to a single instance of the resource), additional new routes (those that apply to creating a new resource), or additional collection routes (those which apply to the collection of resources as a whole).
576
 
 
577
 
h5. Adding Member Routes
578
 
 
579
 
To add a member route, use the +:member+ option:
580
 
 
581
 
<ruby>
582
 
map.resources :photos, :member => { :preview => :get }
583
 
</ruby>
584
 
 
585
 
This will enable Rails to recognize URLs such as +/photos/1/preview+ using the GET HTTP verb, and route them to the preview action of the Photos controller. It will also create a +preview_photo+ route helper.
586
 
 
587
 
Within the hash of member routes, each route name specifies the HTTP verb that it will recognize. You can use +:get+, +:put+, +:post+, +:delete+, or +:any+ here. You can also specify an array of methods, if you need more than one but you don't want to allow just anything:
588
 
 
589
 
<ruby>
590
 
map.resources :photos, :member => { :prepare => [:get, :post] }
591
 
</ruby>
592
 
 
593
 
h5. Adding Collection Routes
594
 
 
595
 
To add a collection route, use the +:collection+ option:
596
 
 
597
 
<ruby>
598
 
map.resources :photos, :collection => { :search => :get }
599
 
</ruby>
600
 
 
601
 
This will enable Rails to recognize URLs such as +/photos/search+ using the GET HTTP verb, and route them to the search action of the Photos controller. It will also create a +search_photos+ route helper.
602
 
 
603
 
Just as with member routes, you can specify an array of methods for a collection route:
604
 
 
605
 
<ruby>
606
 
map.resources :photos, :collection => { :search => [:get, :post] }
607
 
</ruby>
608
 
 
609
 
h5. Adding New Routes
610
 
 
611
 
To add a new route (one that creates a new resource), use the +:new+ option:
612
 
 
613
 
<ruby>
614
 
map.resources :photos, :new => { :upload => :post }
615
 
</ruby>
616
 
 
617
 
This will enable Rails to recognize URLs such as +/photos/upload+ using the POST HTTP verb, and route them to the upload action of the Photos controller. It will also create a +upload_photos+ route helper.
618
 
 
619
 
TIP: If you want to redefine the verbs accepted by one of the standard actions, you can do so by explicitly mapping that action. For example:<br/>+map.resources :photos, :new => { :new => :any }+<br/>This will allow the new action to be invoked by any request to +photos/new+, no matter what HTTP verb you use.
620
 
 
621
 
h5. A Note of Caution
622
 
 
623
 
If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +:member+ and +:collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points.
624
 
 
625
 
h3. Regular Routes
626
 
 
627
 
In addition to RESTful routing, Rails supports regular routing - a way to map URLs to controllers and actions. With regular routing, you don't get the masses of routes automatically generated by RESTful routing. Instead, you must set up each route within your application separately.
628
 
 
629
 
While RESTful routing has become the Rails standard, there are still plenty of places where the simpler regular routing works fine. You can even mix the two styles within a single application. In general, you should prefer RESTful routing _when possible_, because it will make parts of your application easier to write. But there's no need to try to shoehorn every last piece of your application into a RESTful framework if that's not a good fit.
630
 
 
631
 
h4. Bound Parameters
632
 
 
633
 
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:
634
 
 
635
 
<ruby>
636
 
map.connect ':controller/:action/:id'
637
 
</ruby>
638
 
 
639
 
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 +Photos+ controller, and to make the final parameter (1) available as +params[:id]+.
640
 
 
641
 
h4. Wildcard Components
642
 
 
643
 
You can set up as many wildcard symbols within a regular route as you like. Anything other than +:controller+ or +:action+ will be available to the matching action as part of the params hash. So, if you set up this route:
644
 
 
645
 
<ruby>
646
 
map.connect ':controller/:action/:id/:user_id'
647
 
</ruby>
648
 
 
649
 
An incoming URL of +/photos/show/1/2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be set to 2.
650
 
 
651
 
h4. Static Text
652
 
 
653
 
You can specify static text when creating a route. In this case, the static text is used only for matching the incoming requests:
654
 
 
655
 
<ruby>
656
 
map.connect ':controller/:action/:id/with_user/:user_id'
657
 
</ruby>
658
 
 
659
 
This route would respond to URLs such as +/photos/show/1/with_user/2+.
660
 
 
661
 
h4. Querystring Parameters
662
 
 
663
 
Rails routing automatically picks up querystring parameters and makes them available in the +params+ hash. For example, with this route:
664
 
 
665
 
<ruby>
666
 
map.connect ':controller/:action/:id'
667
 
</ruby>
668
 
 
669
 
An incoming URL of +/photos/show/1?user_id=2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be equal to 2.
670
 
 
671
 
h4. Defining Defaults
672
 
 
673
 
You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply defaults for these two parameters in a hash:
674
 
 
675
 
<ruby>
676
 
map.connect 'photos/:id', :controller => 'photos', :action => 'show'
677
 
</ruby>
678
 
 
679
 
With this route, an incoming URL of +/photos/12+ would be dispatched to the +show+ action within the +Photos+ controller.
680
 
 
681
 
You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that are not explicitly defined elsewhere in the route. For example:
682
 
 
683
 
<ruby>
684
 
map.connect 'photos/:id', :controller => 'photos', :action => 'show',
685
 
  :defaults => { :format => 'jpg' }
686
 
</ruby>
687
 
 
688
 
With this route, an incoming URL of +photos/12+ would be dispatched to the +show+ action within the +Photos+ controller, and +params[:format]+ will be set to +jpg+.
689
 
 
690
 
h4. Named Routes
691
 
 
692
 
Regular routes need not use the +connect+ method. You can use any other name here to create a _named route_. For example,
693
 
 
694
 
<ruby>
695
 
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
696
 
</ruby>
697
 
 
698
 
This will do two things. First, requests to +/logout+ will be sent to the +destroy+ method of the +Sessions+ controller. Second, Rails will maintain the +logout_path+ and +logout_url+ helpers for use within your code.
699
 
 
700
 
h4. Route Requirements
701
 
 
702
 
You can use the +:requirements+ option to enforce a format for any parameter in a route:
703
 
 
704
 
<ruby>
705
 
map.connect 'photo/:id', :controller => 'photos', :action => 'show',
706
 
 :requirements => { :id => /[A-Z]\d{5}/ }
707
 
</ruby>
708
 
 
709
 
This route would respond to URLs such as +/photo/A12345+. You can more succinctly express the same route this way:
710
 
 
711
 
<ruby>
712
 
map.connect 'photo/:id', :controller => 'photos', :action => 'show',
713
 
  :id => /[A-Z]\d{5}/
714
 
</ruby>
715
 
 
716
 
h4. Route Conditions
717
 
 
718
 
Route conditions (introduced with the +:conditions+ option) are designed to implement restrictions on routes. Currently, the only supported restriction is +:method+:
719
 
 
720
 
<ruby>
721
 
map.connect 'photo/:id', :controller => 'photos', :action => 'show',
722
 
 :conditions => { :method => :get }
723
 
</ruby>
724
 
 
725
 
As with conditions in RESTful routes, you can specify +:get+, +:post+, +:put+, +:delete+, or +:any+ for the acceptable method.
726
 
 
727
 
h4. Route Globbing
728
 
 
729
 
Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example
730
 
 
731
 
<ruby>
732
 
map.connect 'photo/*other', :controller => 'photos', :action => 'unknown',
733
 
</ruby>
734
 
 
735
 
This route would match +photo/12+ or +/photo/long/path/to/12+ equally well, creating an array of path segments as the value of +params[:other]+.
736
 
 
737
 
h4. Route Options
738
 
 
739
 
You can use +:with_options+ to simplify defining groups of similar routes:
740
 
 
741
 
<ruby>
742
 
map.with_options :controller => 'photo' do |photo|
743
 
  photo.list '', :action => 'index'
744
 
  photo.delete ':id/delete', :action => 'delete'
745
 
  photo.edit ':id/edit', :action => 'edit'
746
 
end
747
 
</ruby>
748
 
 
749
 
The importance of +map.with_options+ has declined with the introduction of RESTful routes.
750
 
 
751
 
h3. Formats and +respond_to+
752
 
 
753
 
There's one more way in which routing can do different things depending on differences in the incoming HTTP request: by issuing a response that corresponds to what the request specifies that it will accept. In Rails routing, you can control this with the special +:format+ parameter in the route.
754
 
 
755
 
For instance, consider the second of the default routes in the boilerplate +routes.rb+ file:
756
 
 
757
 
<ruby>
758
 
map.connect ':controller/:action/:id.:format'
759
 
</ruby>
760
 
 
761
 
This route matches requests such as +/photo/edit/1.xml+ or +/photo/show/2.rss+. Within the appropriate action code, you can issue different responses depending on the requested format:
762
 
 
763
 
<ruby>
764
 
respond_to do |format|
765
 
  format.html # return the default template for HTML
766
 
  format.xml { render :xml => @photo.to_xml }
767
 
end
768
 
</ruby>
769
 
 
770
 
h4. Specifying the Format with an HTTP Header
771
 
 
772
 
If there is no +:format+ parameter in the route, Rails will automatically look at the HTTP Accept header to determine the desired format.
773
 
 
774
 
h4. Recognized MIME types
775
 
 
776
 
By default, Rails recognizes +html+, +text+, +json+, +csv+, +xml+, +rss+, +atom+, and +yaml+ as acceptable response types. If you need types beyond this, you can register them in your environment:
777
 
 
778
 
<ruby>
779
 
Mime::Type.register "image/jpg", :jpg
780
 
</ruby>
781
 
 
782
 
h3. The Default Routes
783
 
 
784
 
When you create a new Rails application, +routes.rb+ is initialized with two default routes:
785
 
 
786
 
<ruby>
787
 
map.connect ':controller/:action/:id'
788
 
map.connect ':controller/:action/:id.:format'
789
 
</ruby>
790
 
 
791
 
These routes provide reasonable defaults for many URLs, if you're not using RESTful routing.
792
 
 
793
 
NOTE: The default routes will make every action of every controller in your application accessible to GET requests. If you've designed your application to make consistent use of RESTful and named routes, you should comment out the default routes to prevent access to your controllers through the wrong verbs. If you've had the default routes enabled during development, though, you need to be sure that you haven't unwittingly depended on them somewhere in your application - otherwise you may find mysterious failures when you disable them.
794
 
 
795
 
h3. The Empty Route
796
 
 
797
 
Don't confuse the default routes with the empty route. The empty route has one specific purpose: to route requests that come in to the root of the web site. For example, if your site is example.com, then requests to +http://example.com+ or +http://example.com/+ will be handled by the empty route.
798
 
 
799
 
h4. Using +map.root+
800
 
 
801
 
The preferred way to set up the empty route is with the +map.root+ command:
802
 
 
803
 
<ruby>
804
 
map.root :controller => "pages", :action => "main"
805
 
</ruby>
806
 
 
807
 
The use of the +root+ method tells Rails that this route applies to requests for the root of the site.
808
 
 
809
 
For better readability, you can specify an already-created route in your call to +map.root+:
810
 
 
811
 
<ruby>
812
 
map.index 'index', :controller => "pages", :action => "main"
813
 
map.root :index
814
 
</ruby>
815
 
 
816
 
Because of the top-down processing of the file, the named route must be specified _before_ the call to +map.root+.
817
 
 
818
 
h4. Connecting the Empty String
819
 
 
820
 
You can also specify an empty route by explicitly connecting the empty string:
821
 
 
822
 
<ruby>
823
 
map.connect '', :controller => "pages", :action => "main"
824
 
</ruby>
825
 
 
826
 
TIP: If the empty route does not seem to be working in your application, make sure that you have deleted the file +public/index.html+ from your Rails tree.
827
 
 
828
 
h3. Inspecting and Testing Routes
829
 
 
830
 
Routing in your application should not be a "black box" that you never open. Rails offers built-in tools for both inspecting and testing routes.
831
 
 
832
 
h4. Seeing Existing Routes with +rake+
833
 
 
834
 
If you want a complete list of all of the available routes in your application, run the +rake routes+ command. This will dump all of your routes to the console, in the same order that they appear in +routes.rb+. For each route, you'll see:
835
 
 
836
 
* The route name (if any)
837
 
* The HTTP verb used (if the route doesn't respond to all verbs)
838
 
* The URL pattern
839
 
* The routing parameters that will be generated by this URL
840
 
 
841
 
For example, here's a small section of the +rake routes+ output for a RESTful route:
842
 
 
843
 
<pre>
844
 
          users GET  /users          {:controller=>"users", :action=>"index"}
845
 
formatted_users GET  /users.:format  {:controller=>"users", :action=>"index"}
846
 
                POST /users          {:controller=>"users", :action=>"create"}
847
 
                POST /users.:format  {:controller=>"users", :action=>"create"}
848
 
</pre>
849
 
 
850
 
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.
851
 
 
852
 
h4. Testing Routes
853
 
 
854
 
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/ActionController/Assertions/RoutingAssertions.html designed to make testing routes simpler:
855
 
 
856
 
* +assert_generates+
857
 
* +assert_recognizes+
858
 
* +assert_routing+
859
 
 
860
 
h5. The +assert_generates+ Assertion
861
 
 
862
 
Use +assert_generates+ to assert that a particular set of options generate a particular path. You can use this with default routes or custom routes
863
 
 
864
 
<ruby>
865
 
assert_generates "/photos/1", { :controller => "photos", :action => "show", :id => "1" }
866
 
assert_generates "/about", :controller => "pages", :action => "about"
867
 
</ruby>
868
 
 
869
 
h5. The +assert_recognizes+ Assertion
870
 
 
871
 
The +assert_recognizes+ assertion is the inverse of +assert_generates+. It asserts that Rails recognizes the given path and routes it to a particular spot in your application.
872
 
 
873
 
<ruby>
874
 
assert_recognizes { :controller => "photos", :action => "show", :id => "1" }, "/photos/1"
875
 
</ruby>
876
 
 
877
 
You can supply a +:method+ argument to specify the HTTP verb:
878
 
 
879
 
<ruby>
880
 
assert_recognizes { :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }
881
 
</ruby>
882
 
 
883
 
You can also use the RESTful helpers to test recognition of a RESTful route:
884
 
 
885
 
<ruby>
886
 
assert_recognizes new_photo_url, { :path => "photos", :method => :post }
887
 
</ruby>
888
 
 
889
 
h5. The +assert_routing+ Assertion
890
 
 
891
 
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+.
892
 
 
893
 
<ruby>
894
 
assert_routing { :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }
895
 
</ruby>
896
 
 
897
 
h3. Changelog
898
 
 
899
 
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/3
900
 
 
901
 
* October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes, by "Mike Gunderloy":credits.html#mgunderloy
902
 
* September 23, 2008: Added section on namespaced controllers and routing, by "Mike Gunderloy":credits.html#mgunderloy
903
 
* September 10, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy