Froze rails gems
[depot.git] / vendor / rails / railties / doc / guides / source / routing_outside_in.txt
1 Rails Routing from the Outside In
2 =================================
3
4 This guide covers the user-facing features of Rails routing. By referring to this guide, you will be able to:
5
6 * Understand the purpose of routing
7 * Decipher the code in +routes.rb+
8 * Construct your own routes, using either the classic hash style or the now-preferred RESTful style
9 * Identify how a route will map to a controller and action
10
11 == The Dual Purpose of Routing
12
13 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.
14
15 === Connecting URLs to Code
16
17 When your Rails application receives an incoming HTTP request, say
18
19 -------------------------------------------------------
20 GET /patients/17
21 -------------------------------------------------------
22
23 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.
24
25 === Generating URLs from Code
26
27 Routing also works in reverse. If your application contains this code:
28
29 [source, ruby]
30 -------------------------------------------------------
31 @patient = Patient.find(17)
32 <%= link_to "Patient Record", patient_path(@patient) %>
33 -------------------------------------------------------
34
35 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.
36
37 NOTE: Patient needs to be declared as a resource for this style of translation via a named route to be available.
38
39 == Quick Tour of Routes.rb
40
41 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.
42
43 === Processing the File
44
45 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:
46
47 * RESTful Routes
48 * Named Routes
49 * Nested Routes
50 * Regular Routes
51 * Default Routes
52
53 Each of these types of route is covered in more detail later in this guide.
54
55 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.
56
57 === RESTful Routes
58
59 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:
60
61 [source, ruby]
62 -------------------------------------------------------
63 map.resources :books
64 -------------------------------------------------------
65
66 === Named Routes
67
68 Named routes give you very readable links in your code, as well as handling incoming requests. Here's a typical named route:
69
70 [source, ruby]
71 -------------------------------------------------------
72 map.login '/login', :controller => 'sessions', :action => 'new'
73 -------------------------------------------------------
74
75 === Nested Routes
76
77 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:
78
79 [source, ruby]
80 -------------------------------------------------------
81 map.resources :assemblies do |assemblies|
82 assemblies.resources :parts
83 end
84 -------------------------------------------------------
85
86 === 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 [source, ruby]
91 -------------------------------------------------------
92 map.connect 'parts/:number', :controller => 'inventory', :action => 'show'
93 -------------------------------------------------------
94
95 === Default Routes
96
97 The default routes are a safety net that catch otherwise-unrouted requests. Many Rails applications will contain this pair of default routes:
98
99 [source, ruby]
100 -------------------------------------------------------
101 map.connect ':controller/:action/:id'
102 map.connect ':controller/:action/:id.:format'
103 -------------------------------------------------------
104
105 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!
106
107 == RESTful Routing: the Rails Default
108
109 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.
110
111 === What is REST?
112
113 The foundation of RESTful routing is generally considered to be Roy Fielding's doctoral thesis, link:http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm[Architectural Styles and the Design of Network-based Software Architectures]. 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:
114
115 * Using resource identifiers (which, for the purposes of discussion, you can think of as URLs) to represent resources
116 * Transferring representations of the state of that resource between system components.
117
118 For example, to a Rails application a request such as this:
119
120 +DELETE /photos/17+
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 === 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 [source, ruby]
129 -------------------------------------------------------
130 map.resources :photos
131 -------------------------------------------------------
132
133 creates seven different routes in your application:
134
135 [grid="all"]
136 `----------`---------------`-----------`--------`-------------------------------------------
137 HTTP verb URL controller action used for
138 --------------------------------------------------------------------------------------------
139 GET /photos Photos index display a list of all photos
140 GET /photos/new Photos new return an HTML form for creating a new photo
141 POST /photos Photos create create a new photo
142 GET /photos/1 Photos show display a specific photo
143 GET /photos/1/edit Photos edit return an HTML form for editing a photo
144 PUT /photos/1 Photos update update a specific photo
145 DELETE /photos/1 Photos destroy delete a specific photo
146 --------------------------------------------------------------------------------------------
147
148 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]+.
149
150 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.
151
152 === URLs and Paths
153
154 Creating a RESTful route will also make available a pile of helpers within your application:
155
156 * +photos_url+ and +photos_path+ map to the path for the index and create actions
157 * +new_photo_url+ and +new_photo_path+ map to the path for the new action
158 * +edit_photo_url+ and +edit_photo_path+ map to the path for the edit action
159 * +photo_url+ and +photo_path+ map to the path for the show, update, and destroy actions
160
161 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.
162
163 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:
164
165 [source, ruby]
166 -------------------------------------------------------
167 photos_url # => "http://www.example.com/photos"
168 photos_path # => "/photos"
169 -------------------------------------------------------
170
171 === Defining Multiple Resources at the Same Time
172
173 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+:
174
175 [source, ruby]
176 -------------------------------------------------------
177 map.resources :photos, :books, :videos
178 -------------------------------------------------------
179
180 This has exactly the same effect as
181
182 [source, ruby]
183 -------------------------------------------------------
184 map.resources :photos
185 map.resources :books
186 map.resources :videos
187 -------------------------------------------------------
188
189 === Singular Resources
190
191 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
192
193 [source, ruby]
194 -------------------------------------------------------
195 map.resource :geocoder
196 -------------------------------------------------------
197
198 creates six different routes in your application:
199
200 [grid="all"]
201 `----------`---------------`-----------`--------`-------------------------------------------
202 HTTP verb URL controller action used for
203 --------------------------------------------------------------------------------------------
204 GET /geocoder/new Geocoders new return an HTML form for creating the new geocoder
205 POST /geocoder Geocoders create create the new geocoder
206 GET /geocoder Geocoders show display the one and only geocoder resource
207 GET /geocoder/edit Geocoders edit return an HTML form for editing the geocoder
208 PUT /geocoder Geocoders update update the one and only geocoder resource
209 DELETE /geocoder Geocoders destroy delete the geocoder resource
210 --------------------------------------------------------------------------------------------
211
212 NOTE: Even though the name of the resource is singular in +routes.rb+, the matching controller is still plural.
213
214 A singular RESTful route generates an abbreviated set of helpers:
215
216 * +new_geocoder_url+ and +new_geocoder_path+ map to the path for the new action
217 * +edit_geocoder_url+ and +edit_geocoder_path+ map to the path for the edit action
218 * +geocoder_url+ and +geocoder_path+ map to the path for the create, show, update, and destroy actions
219
220 === Customizing Resources
221
222 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:
223
224 * +:controller+
225 * +:singular+
226 * +:requirements+
227 * +:conditions+
228 * +:as+
229 * +:path_names+
230 * +:path_prefix+
231 * +:name_prefix+
232 * +:only+
233 * +:except+
234
235 You can also add additional routes via the +:member+ and +:collection+ options, which are discussed later in this guide.
236
237 ==== Using :controller
238
239 The +:controller+ option lets you use a controller name that is different from the public-facing resource name. For example, this routing entry:
240
241 [source, ruby]
242 -------------------------------------------------------
243 map.resources :photos, :controller => "images"
244 -------------------------------------------------------
245
246 will recognize incoming URLs containing +photo+ but route the requests to the Images controller:
247
248 [grid="all"]
249 `----------`---------------`-----------`--------`-------------------------------------------
250 HTTP verb URL controller action used for
251 --------------------------------------------------------------------------------------------
252 GET /photos Images index display a list of all images
253 GET /photos/new Images new return an HTML form for creating a new image
254 POST /photos Images create create a new image
255 GET /photos/1 Images show display a specific image
256 GET /photos/1/edit Images edit return an HTML form for editing a image
257 PUT /photos/1 Images update update a specific image
258 DELETE /photos/1 Images destroy delete a specific image
259 --------------------------------------------------------------------------------------------
260
261 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.
262
263 === Controller Namespaces and Routing ===
264
265 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:
266
267 [source, ruby]
268 -------------------------------------------------------
269 map.resources :adminphotos, :controller => "admin/photos"
270 -------------------------------------------------------
271
272 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 +<%= link_to "show", adminphoto(1) %>+ 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 +<%= link_to "show", {:controller => "photos", :action => "show"} %>+ because Rails will generate the show URL relative to the current URL.
273
274 TIP: If you want to guarantee that a link goes to a top-level controller, use a preceding slash to anchor the controller name: +<%= link_to "show", {:controller => "/photos", :action => "show"} %>+
275
276 You can also specify a controller namespace with the +:namespace+ option instead of a path:
277
278 [source, ruby]
279 -------------------------------------------------------
280 map.resources :adminphotos, :namespace => "admin", :controller => "photos"
281 -------------------------------------------------------
282
283 This can be especially useful when combined with +with_options+ to map multiple namespaced routes together:
284
285 [source, ruby]
286 -------------------------------------------------------
287 map.with_options(:namespace => "admin") do |admin|
288 admin.resources :photos, :videos
289 end
290 -------------------------------------------------------
291
292 That would give you routing for +admin/photos+ and +admin/videos+ controllers.
293
294 ==== Using :singular
295
296 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:
297
298 [source, ruby]
299 -------------------------------------------------------
300 map.resources :teeth, :singular => "tooth"
301 -------------------------------------------------------
302
303 TIP: Depending on the other code in your application, you may prefer to add additional rules to the +Inflector+ class instead.
304
305 ==== Using :requirements
306
307 You an use the +:requirements+ option in a RESTful route to impose a format on the implied +:id+ parameter in the singular routes. For example:
308
309 [source, ruby]
310 -------------------------------------------------------
311 map.resources :photos, :requirements => {:id => /[A-Z][A-Z][0-9]+/}
312 -------------------------------------------------------
313
314 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.
315
316 ==== Using :conditions
317
318 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.)
319
320 ==== Using :as
321
322 The +:as+ option lets you override the normal naming for the actual generated paths. For example:
323
324 [source, ruby]
325 -------------------------------------------------------
326 map.resources :photos, :as => "images"
327 -------------------------------------------------------
328
329 will recognize incoming URLs containing +image+ but route the requests to the Photos controller:
330
331 [grid="all"]
332 `----------`---------------`-----------`--------`-------------------------------------------
333 HTTP verb URL controller action used for
334 --------------------------------------------------------------------------------------------
335 GET /images Photos index display a list of all photos
336 GET /images/new Photos new return an HTML form for creating a new photo
337 POST /images Photos create create a new photo
338 GET /images/1 Photos show display a specific photo
339 GET /images/1/edit Photos edit return an HTML form for editing a photo
340 PUT /images/1 Photos update update a specific photo
341 DELETE /images/1 Photos destroy delete a specific photo
342 --------------------------------------------------------------------------------------------
343
344 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.
345
346 ==== Using :path_names
347
348 The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in URLs:
349
350 [source, ruby]
351 -------------------------------------------------------
352 map.resources :photos, :path_names => { :new => 'make', :edit => 'change' }
353 -------------------------------------------------------
354
355 This would cause the routing to recognize URLs such as
356
357 -------------------------------------------------------
358 /photos/make
359 /photos/1/change
360 -------------------------------------------------------
361
362 NOTE: The actual action names aren't changed by this option; the two URLs show would still route to the new and edit actions.
363
364 TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can set a default in your environment:
365
366 [source, ruby]
367 -------------------------------------------------------
368 config.action_controller.resources_path_names = { :new => 'make', :edit => 'change' }
369 -------------------------------------------------------
370
371 ==== Using :path_prefix
372
373 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:
374
375 [source, ruby]
376 -------------------------------------------------------
377 map.resources :photos, :path_prefix => '/photographers/:photographer_id'
378 -------------------------------------------------------
379
380 Routes recognized by this entry would include:
381
382 -------------------------------------------------------
383 /photographers/1/photos/2
384 /photographers/1/photos
385 -------------------------------------------------------
386
387 NOTE: In most cases, it's simpler to recognize URLs of this sort by creating nested resources, as discussed in the next section.
388
389 NOTE: You can also use +:path_prefix+ with non-RESTful routes.
390
391 ==== Using :name_prefix
392
393 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:
394
395 [source, ruby]
396 -------------------------------------------------------
397 map.resources :photos, :path_prefix => '/photographers/:photographer_id', :name_prefix => 'photographer_'
398 map.resources :photos, :path_prefix => '/agencies/:agency_id', :name_prefix => 'agency_'
399 -------------------------------------------------------
400
401 This combination will give you route helpers such as +photographer_photos_path+ and +agency_edit_photo_path+ to use in your code.
402
403 NOTE: You can also use +:name_prefix+ with non-RESTful routes.
404
405 ==== Using :only and :except
406
407 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:
408
409 [source, ruby]
410 -------------------------------------------------------
411 map.resources :photos, :only => [:index, :show]
412 -------------------------------------------------------
413
414 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.
415
416 The +:except+ option specifies a route or list of routes that should _not_ be generated:
417
418 [source, ruby]
419 -------------------------------------------------------
420 map.resources :photos, :except => :destroy
421 -------------------------------------------------------
422
423 In this case, all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/_id_+) will be generated.
424
425 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.
426
427 TIP: If your application has many RESTful routes, using +:only+ and +:accept+ to generate only the routes that you actually need can cut down on memory use and speed up the routing process.
428
429 === Nested Resources
430
431 It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:
432
433 [source, ruby]
434 -------------------------------------------------------
435 class Magazine < ActiveRecord::Base
436 has_many :ads
437 end
438
439 class Ad < ActiveRecord::Base
440 belongs_to :magazine
441 end
442 -------------------------------------------------------
443
444 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:
445
446 [source, ruby]
447 -------------------------------------------------------
448 map.resources :magazines do |magazine|
449 magazine.resources :ads
450 end
451 -------------------------------------------------------
452
453 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:
454
455 [grid="all"]
456 `----------`-----------------------`-----------`--------`-------------------------------------------
457 HTTP verb URL controller action used for
458 --------------------------------------------------------------------------------------------
459 GET /magazines/1/ads Ads index display a list of all ads for a specific magazine
460 GET /magazines/1/ads/new Ads new return an HTML form for creating a new ad belonging to a specific magazine
461 POST /magazines/1/ads Ads create create a new ad belonging to a specific magazine
462 GET /magazines/1/ads/1 Ads show display a specific ad belonging to a specific magazine
463 GET /magazines/1/ads/1/edit Ads edit return an HTML form for editing an ad belonging to a specific magazine
464 PUT /magazines/1/ads/1 Ads update update a specific ad belonging to a specific magazine
465 DELETE /magazines/1/ads/1 Ads destroy delete a specific ad belonging to a specific magazine
466 --------------------------------------------------------------------------------------------
467
468 This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+.
469
470 ==== Using :name_prefix
471
472 The +:name_prefix+ option overrides the automatically-generated prefix in nested route helpers. For example,
473
474 [source, ruby]
475 -------------------------------------------------------
476 map.resources :magazines do |magazine|
477 magazine.resources :ads, :name_prefix => 'periodical'
478 end
479 -------------------------------------------------------
480
481 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:
482
483 [source, ruby]
484 -------------------------------------------------------
485 map.resources :magazines do |magazine|
486 magazine.resources :ads, :name_prefix => nil
487 end
488 -------------------------------------------------------
489
490 This will create routing helpers such as +ads_url+ and +edit_ad_path+. Note that calling these will still require supplying an article id:
491
492 [source, ruby]
493 -------------------------------------------------------
494 ads_url(@magazine)
495 edit_ad_path(@magazine, @ad)
496 -------------------------------------------------------
497
498 ==== Using :has_one and :has_many
499
500 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:
501
502 [source, ruby]
503 -------------------------------------------------------
504 map.resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
505 -------------------------------------------------------
506
507 This has the same effect as this set of declarations:
508
509 [source, ruby]
510 -------------------------------------------------------
511 map.resources :photos do |photo|
512 photo.resource :photographer
513 photo.resources :publications
514 photo.resources :versions
515 end
516 -------------------------------------------------------
517
518 ==== Limits to Nesting
519
520 You can nest resources within other nested resources if you like. For example:
521
522 [source, ruby]
523 -------------------------------------------------------
524 map.resources :publishers do |publisher|
525 publisher.resources :magazines do |magazine|
526 magazine.resources :photos
527 end
528 end
529 -------------------------------------------------------
530
531 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
532
533 -------------------------------------------------------
534 /publishers/1/magazines/2/photos/3
535 -------------------------------------------------------
536
537 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 link:http://weblog.jamisbuck.org/2007/2/5/nesting-resources[article] by Jamis Buck proposes a rule of thumb for good Rails design:
538
539 _Resources should never be nested more than 1 level deep._
540
541 ==== Shallow Nesting
542
543 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:
544
545 [source, ruby]
546 -------------------------------------------------------
547 map.resources :publishers, :shallow => true do |publisher|
548 publisher.resources :magazines do |magazine|
549 magazine.resources :photos
550 end
551 end
552 -------------------------------------------------------
553
554 This will enable recognition of (among others) these routes:
555
556 -------------------------------------------------------
557 /publishers/1 ==> publisher_path(1)
558 /publishers/1/magazines ==> publisher_magazines_path(1)
559 /magazines/2 ==> magazine_path(2)
560 /magazines/2/photos ==> magazines_photos_path(2)
561 /photos/3 ==> photo_path(3)
562 -------------------------------------------------------
563
564 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:
565
566 [source, ruby]
567 -------------------------------------------------------
568 map.resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
569 -------------------------------------------------------
570
571 === Route Generation from Arrays
572
573 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:
574
575 [source, ruby]
576 -------------------------------------------------------
577 map.resources :magazines do |magazine|
578 magazine.resources :ads
579 end
580 -------------------------------------------------------
581
582 Rails will generate helpers such as magazine_ad_path that you can use in building links:
583
584 [source, ruby]
585 -------------------------------------------------------
586 <%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %>
587 -------------------------------------------------------
588
589 Another way to refer to the same route is with an array of objects:
590
591 [source, ruby]
592 -------------------------------------------------------
593 <%= link_to "Ad details", [@magazine, @ad] %>
594 -------------------------------------------------------
595
596 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.
597
598 === Namespaced Resources
599
600 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:
601
602 [source, ruby]
603 -------------------------------------------------------
604 map.resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
605 map.resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
606 map.resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
607 -------------------------------------------------------
608
609 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:
610
611 [source, ruby]
612 -------------------------------------------------------
613 map.namespace(:admin) do |admin|
614 admin.resources :photos,
615 :has_many => { :tags, :ratings}
616 end
617 -------------------------------------------------------
618
619 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.
620
621 === Adding More RESTful Actions
622
623 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).
624
625 ==== Adding Member Routes
626
627 To add a member route, use the +:member+ option:
628
629 [source, ruby]
630 -------------------------------------------------------
631 map.resources :photos, :member => { :preview => :get }
632 -------------------------------------------------------
633
634 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.
635
636 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:
637
638 [source, ruby]
639 -------------------------------------------------------
640 map.resources :photos, :member => { :prepare => [:get, :post] }
641 -------------------------------------------------------
642
643 ==== Adding Collection Routes
644
645 To add a collection route, use the +:collection+ option:
646
647 [source, ruby]
648 -------------------------------------------------------
649 map.resources :photos, :collection => { :search => :get }
650 -------------------------------------------------------
651
652 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.
653
654 Just as with member routes, you can specify an array of methods for a collection route:
655
656 [source, ruby]
657 -------------------------------------------------------
658 map.resources :photos, :collection => { :search => [:get, :post] }
659 -------------------------------------------------------
660
661 ==== Adding New Routes
662
663 To add a new route (one that creates a new resource), use the +:new+ option:
664
665 [source, ruby]
666 -------------------------------------------------------
667 map.resources :photos, :new => { :upload => :post }
668 -------------------------------------------------------
669
670 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.
671
672 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:
673
674 [source, ruby]
675 -------------------------------------------------------
676 map.resources :photos, :new => { :new => :any }
677 -------------------------------------------------------
678
679 This will allow the new action to be invoked by any request to +photos/new+, no matter what HTTP verb you use.
680
681 ==== A Note of Caution
682
683 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.
684
685 == Regular Routes
686
687 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.
688
689 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.
690
691 === Bound Parameters
692
693 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:
694
695 [source, ruby]
696 -------------------------------------------------------
697 map.connect ':controller/:action/:id'
698 -------------------------------------------------------
699
700 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]+.
701
702 === Wildcard Components
703
704 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:
705
706 [source, ruby]
707 -------------------------------------------------------
708 map.connect ':controller/:action/:id/:user_id'
709 -------------------------------------------------------
710
711 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.
712
713 === Static Text
714
715 You can specify static text when creating a route. In this case, the static text is used only for matching the incoming requests:
716
717 [source, ruby]
718 -------------------------------------------------------
719 map.connect ':controller/:action/:id/with_user/:user_id'
720 -------------------------------------------------------
721
722 This route would respond to URLs such as +/photos/show/1/with_user/2+.
723
724 === Querystring Parameters
725
726 Rails routing automatically picks up querystring parameters and makes them available in the +params+ hash. For example, with this route:
727
728 [source, ruby]
729 -------------------------------------------------------
730 map.connect ':controller/:action/:id'
731 -------------------------------------------------------
732
733 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.
734
735 === Defining Defaults
736
737 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:
738
739 [source, ruby]
740 -------------------------------------------------------
741 map.connect 'photo/:id', :controller => 'photos', :action => 'show'
742 -------------------------------------------------------
743
744 With this route, an incoming URL of +/photos/12+ would be dispatched to the +show+ action within the +Photos+ controller.
745
746 You an 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:
747
748 [source, ruby]
749 -------------------------------------------------------
750 map.connect 'photo/:id', :controller => 'photos', :action => 'show', :defaults => { :format => 'jpg' }
751 -------------------------------------------------------
752
753 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+.
754
755 === Named Routes
756
757 Regular routes need not use the +connect+ method. You can use any other name here to create a _named route_. For example,
758
759 [source, ruby]
760 -------------------------------------------------------
761 map.logout '/logout', :controller => 'sessions', :action => 'destroy'
762 -------------------------------------------------------
763
764 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.
765
766 === Route Requirements
767
768 You can use the +:requirements+ option to enforce a format for any parameter in a route:
769
770 [source, ruby]
771 -------------------------------------------------------
772 map.connect 'photo/:id', :controller => 'photos', :action => 'show',
773 :requirements => { :id => /[A-Z]\d{5}/ }
774 -------------------------------------------------------
775
776 This route would respond to URLs such as +/photo/A12345+. You can more succinctly express the same route this way:
777
778 [source, ruby]
779 -------------------------------------------------------
780 map.connect 'photo/:id', :controller => 'photos', :action => 'show',
781 :id => /[A-Z]\d{5}/
782 -------------------------------------------------------
783
784 === Route Conditions
785
786 Route conditions (introduced with the +:conditions+ option) are designed to implement restrictions on routes. Currently, the only supported restriction is +:method+:
787
788 [source, ruby]
789 -------------------------------------------------------
790 map.connect 'photo/:id', :controller => 'photos', :action => 'show',
791 :conditions => { :method => :get }
792 -------------------------------------------------------
793
794 As with conditions in RESTful routes, you can specify +:get+, +:post+, +:put+, +:delete+, or +:any+ for the acceptable method.
795
796 === Route Globbing
797
798 Route globbing is a way to specify that a particular parameter (which must be the last parameter in the route) should be matched to all the remaining parts of a route. For example
799
800 [source, ruby]
801 -------------------------------------------------------
802 map.connect 'photo/*other', :controller => 'photos', :action => 'unknown',
803 -------------------------------------------------------
804
805 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]+.
806
807 === Route Options
808
809 You can use +:with_options+ to simplify defining groups of similar routes:
810
811 [source, ruby]
812 -------------------------------------------------------
813 map.with_options :controller => 'photo' do |photo|
814 photo.list '', :action => 'index'
815 photo.delete ':id/delete', :action => 'delete'
816 photo.edit ':id/edit', :action => 'edit'
817 end
818 -------------------------------------------------------
819
820 The importance of +map.with_options+ has declined with the introduction of RESTful routes.
821
822 == Formats and respond_to
823
824 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.
825
826 For instance, consider the second of the default routes in the boilerplate +routes.rb+ file:
827
828 [source, ruby]
829 -------------------------------------------------------
830 map.connect ':controller/:action/:id.:format'
831 -------------------------------------------------------
832
833 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:
834
835 [source, ruby]
836 -------------------------------------------------------
837 respond_to do |format|
838 format.html # return the default template for HTML
839 format.xml { render :xml => @photo.to_xml }
840 end
841 -------------------------------------------------------
842
843 === Specifying the Format with an HTTP Header
844
845 If there is no +:format+ parameter in the route, Rails will automatically look at the HTTP Accept header to determine the desired format.
846
847 === Recognized MIME types
848
849 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:
850
851 [source, ruby]
852 -------------------------------------------------------
853 Mime::Type.register "image/jpg", :jpg
854 -------------------------------------------------------
855
856 == The Default Routes
857
858 When you create a new Rails application, +routes.rb+ is initialized with two default routes:
859
860 [source, ruby]
861 -------------------------------------------------------
862 map.connect ':controller/:action/:id'
863 map.connect ':controller/:action/:id.:format'
864 -------------------------------------------------------
865
866 These routes provide reasonable defaults for many URLs, if you're not using RESTful routing.
867
868 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.
869
870 == The Empty Route
871
872 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.
873
874 === Using map.root
875
876 The preferred way to set up the empty route is with the +map.root+ command:
877
878 [source, ruby]
879 -------------------------------------------------------
880 map.root :controller => "pages", :action => "main"
881 -------------------------------------------------------
882
883 The use of the +root+ method tells Rails that this route applies to requests for the root of the site.
884
885 For better readability, you can specify an already-created route in your call to +map.root+:
886
887 [source, ruby]
888 -------------------------------------------------------
889 map.index :controller => "pages", :action => "main"
890 map.root :index
891 -------------------------------------------------------
892
893 Because of the top-down processing of the file, the named route must be specified _before_ the call to +map.root+.
894
895 === Connecting the Empty String
896
897 You can also specify an empty route by explicitly connecting the empty string:
898
899 [source, ruby]
900 -------------------------------------------------------
901 map.connect '', :controller => "pages", :action => "main"
902 -------------------------------------------------------
903
904 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.
905
906 == Inspecting and Testing Routes
907
908 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.
909
910 === Seeing Existing Routes with rake
911
912 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:
913
914 * The route name (if any)
915 * The HTTP verb used (if the route doesn't respond to all verbs)
916 * The URL pattern
917 * The routing parameters that will be generated by this URL
918
919 For example, here's a small section of the +rake routes+ output for a RESTful route:
920
921 -------------------------------------------------------------------------------------------------------
922 users GET /users {:controller=>"users", :action=>"index"}
923 formatted_users GET /users.:format {:controller=>"users", :action=>"index"}
924 POST /users {:controller=>"users", :action=>"create"}
925 POST /users.:format {:controller=>"users", :action=>"create"}
926 -------------------------------------------------------------------------------------------------------
927
928 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.
929
930 === Testing Routes
931
932 Routes should be included in your testing strategy (just like the rest of your application). Rails offers three link:http://api.rubyonrails.com/classes/ActionController/Assertions/RoutingAssertions.html[built-in assertions] designed to make testing routes simpler:
933
934 * +assert_generates+
935 * +assert_recognizes+
936 * +assert_routing+
937
938 ==== The +assert_generates+ Assertion
939
940 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
941
942 [source, ruby]
943 -------------------------------------------------------
944 assert_generates "/photos/1", { :controller => "photos", :action => "show", :id => "1" }
945 assert_generates "/about", :controller => "pages", :action => "about"
946 -------------------------------------------------------
947
948 ==== The +assert_recognizes+ Assertion
949
950 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.
951
952 [source, ruby]
953 -------------------------------------------------------
954 assert_recognizes { :controller => "photos", :action => "show", :id => "1" }, "/photos/1"
955 -------------------------------------------------------
956
957 You can supply a +:method+ argument to specify the HTTP verb:
958
959 [source, ruby]
960 -------------------------------------------------------
961 assert_recognizes { :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }
962 -------------------------------------------------------
963
964 You can also use the RESTful helpers to test recognition of a RESTful route:
965
966 [source, ruby]
967 -------------------------------------------------------
968 assert_recognizes new_photo_url, { :path => "photos", :method => :post }
969 -------------------------------------------------------
970
971 ==== The +assert_routing+ Assertion
972
973 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+.
974
975 [source, ruby]
976 -------------------------------------------------------
977 assert_routing { :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }
978 -------------------------------------------------------
979
980 == Changelog ==
981
982 http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/3[Lighthouse ticket]
983
984 * October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes , by link:../authors.html#mgunderloy[Mike Gunderloy]
985 * September 23, 2008: Added section on namespaced controllers and routing, by link:../authors.html#mgunderloy[Mike Gunderloy]
986 * September 10, 2008: initial version by link:../authors.html#mgunderloy[Mike Gunderloy]