Skip to content
This repository
Browse code

Expanded routing documentation with current best practices

Signed-off-by: Xavier Noria <fxn@hashref.com>
  • Loading branch information...
commit e8d2002f217ae13edffe4f8e5c4c0174276bc03b 1 parent 05bb9ca
Joost Baaij authored August 29, 2010 fxn committed August 31, 2010
19  actionpack/lib/action_dispatch/http/response.rb
@@ -4,27 +4,26 @@
4 4
 require 'active_support/core_ext/class/attribute_accessors'
5 5
 
6 6
 module ActionDispatch # :nodoc:
7  
-  # Represents an HTTP response generated by a controller action. One can use
8  
-  # an ActionDispatch::Response object to retrieve the current state
9  
-  # of the response, or customize the response. An Response object can
10  
-  # either represent a "real" HTTP response (i.e. one that is meant to be sent
11  
-  # back to the web browser) or a test response (i.e. one that is generated
12  
-  # from integration tests). See CgiResponse and TestResponse, respectively.
  7
+  # Represents an HTTP response generated by a controller action. Use it to
  8
+  # retrieve the current state of the response, or customize the response. It can
  9
+  # either represent a real HTTP response (i.e. one that is meant to be sent
  10
+  # back to the web browser) or a TestResponse (i.e. one that is generated
  11
+  # from integration tests).
13 12
   #
14  
-  # Response is mostly a Ruby on Rails framework implement detail, and
  13
+  # \Response is mostly a Ruby on \Rails framework implementation detail, and
15 14
   # should never be used directly in controllers. Controllers should use the
16 15
   # methods defined in ActionController::Base instead. For example, if you want
17 16
   # to set the HTTP response's content MIME type, then use
18 17
   # ActionControllerBase#headers instead of Response#headers.
19 18
   #
20 19
   # Nevertheless, integration tests may want to inspect controller responses in
21  
-  # more detail, and that's when Response can be useful for application
  20
+  # more detail, and that's when \Response can be useful for application
22 21
   # developers. Integration test methods such as
23 22
   # ActionDispatch::Integration::Session#get and
24 23
   # ActionDispatch::Integration::Session#post return objects of type
25  
-  # TestResponse (which are of course also of type Response).
  24
+  # TestResponse (which are of course also of type \Response).
26 25
   #
27  
-  # For example, the following demo integration "test" prints the body of the
  26
+  # For example, the following demo integration test prints the body of the
28 27
   # controller response to the console:
29 28
   #
30 29
   #  class DemoControllerTest < ActionDispatch::IntegrationTest
169  actionpack/lib/action_dispatch/routing/mapper.rb
@@ -226,10 +226,24 @@ def initialize(set) #:nodoc:
226 226
           @set = set
227 227
         end
228 228
 
  229
+        # You can specify what Rails should route "/" to with the root method:
  230
+        #
  231
+        #   root :to => 'pages#main'
  232
+        #
  233
+        # You should put the root route at the end of <tt>config/routes.rb</tt>.
229 234
         def root(options = {})
230 235
           match '/', options.reverse_merge(:as => :root)
231 236
         end
232 237
 
  238
+        # When you set up a regular route, you supply a series of symbols that
  239
+        # Rails maps to parts of an incoming HTTP request.
  240
+        #
  241
+        #   match ':controller/:action/:id/:user_id'
  242
+        #
  243
+        # Two of these symbols are special: :controller maps to the name of a
  244
+        # controller in your application, and :action maps to the name of an
  245
+        # action within that controller. Anything other than :controller or
  246
+        # :action will be available to the action as part of params.
233 247
         def match(path, options=nil)
234 248
           mapping = Mapping.new(@set, @scope, path, options || {}).to_route
235 249
           @set.add_route(*mapping)
@@ -258,22 +272,29 @@ def default_url_options=(options)
258 272
       end
259 273
 
260 274
       module HttpHelpers
  275
+        # Define a route that only recognizes HTTP GET.
261 276
         def get(*args, &block)
262 277
           map_method(:get, *args, &block)
263 278
         end
264 279
 
  280
+        # Define a route that only recognizes HTTP POST.
265 281
         def post(*args, &block)
266 282
           map_method(:post, *args, &block)
267 283
         end
268 284
 
  285
+        # Define a route that only recognizes HTTP PUT.
269 286
         def put(*args, &block)
270 287
           map_method(:put, *args, &block)
271 288
         end
272 289
 
  290
+        # Define a route that only recognizes HTTP DELETE.
273 291
         def delete(*args, &block)
274 292
           map_method(:delete, *args, &block)
275 293
         end
276 294
 
  295
+        # Redirect any path to another path:
  296
+        #
  297
+        #   match "/stories" => redirect("/posts")
277 298
         def redirect(*args, &block)
278 299
           options = args.last.is_a?(Hash) ? args.pop : {}
279 300
 
@@ -314,12 +335,72 @@ def map_method(method, *args, &block)
314 335
           end
315 336
       end
316 337
 
  338
+      # You may wish to organize groups of controllers under a namespace.
  339
+      # Most commonly, you might group a number of administrative controllers
  340
+      # under an +admin+ namespace. You would place these controllers under
  341
+      # the app/controllers/admin directory, and you can group them together
  342
+      # in your router:
  343
+      #
  344
+      #   namespace "admin" do
  345
+      #     resources :posts, :comments
  346
+      #   end
  347
+      # 
  348
+      # This will create a number of routes for each of the posts and comments
  349
+      # controller. For Admin::PostsController, Rails will create:
  350
+      # 
  351
+      #   GET	    /admin/photos
  352
+      #   GET	    /admin/photos/new
  353
+      #   POST	  /admin/photos
  354
+      #   GET	    /admin/photos/1
  355
+      #   GET	    /admin/photos/1/edit
  356
+      #   PUT	    /admin/photos/1
  357
+      #   DELETE  /admin/photos/1
  358
+      # 
  359
+      # If you want to route /photos (without the prefix /admin) to
  360
+      # Admin::PostsController, you could use
  361
+      # 
  362
+      #   scope :module => "admin" do
  363
+      #     resources :posts, :comments
  364
+      #   end
  365
+      #
  366
+      # or, for a single case
  367
+      # 
  368
+      #   resources :posts, :module => "admin"
  369
+      # 
  370
+      # If you want to route /admin/photos to PostsController
  371
+      # (without the Admin:: module prefix), you could use
  372
+      # 
  373
+      #   scope "/admin" do
  374
+      #     resources :posts, :comments
  375
+      #   end
  376
+      #
  377
+      # or, for a single case
  378
+      # 
  379
+      #   resources :posts, :path => "/admin"
  380
+      #
  381
+      # In each of these cases, the named routes remain the same as if you did
  382
+      # not use scope. In the last case, the following paths map to
  383
+      # PostsController:
  384
+      # 
  385
+      #   GET	    /admin/photos
  386
+      #   GET	    /admin/photos/new
  387
+      #   POST	  /admin/photos
  388
+      #   GET	    /admin/photos/1
  389
+      #   GET	    /admin/photos/1/edit
  390
+      #   PUT	    /admin/photos/1
  391
+      #   DELETE  /admin/photos/1
317 392
       module Scoping
318 393
         def initialize(*args) #:nodoc:
319 394
           @scope = {}
320 395
           super
321 396
         end
322 397
 
  398
+        # Used to route <tt>/photos</tt> (without the prefix <tt>/admin</tt>)
  399
+        # to Admin::PostsController:
  400
+        #
  401
+        #   scope :module => "admin" do
  402
+        #     resources :posts
  403
+        #   end
323 404
         def scope(*args)
324 405
           options = args.extract_options!
325 406
           options = options.dup
@@ -441,6 +522,37 @@ def override_keys(child)
441 522
           end
442 523
       end
443 524
 
  525
+      # Resource routing allows you to quickly declare all of the common routes
  526
+      # for a given resourceful controller. Instead of declaring separate routes
  527
+      # for your +index+, +show+, +new+, +edit+, +create+, +update+ and +destroy+
  528
+      # actions, a resourceful route declares them in a single line of code:
  529
+      #
  530
+      #  resources :photos
  531
+      #
  532
+      # Sometimes, you have a resource that clients always look up without
  533
+      # referencing an ID. A common example, /profile always shows the profile of
  534
+      # the currently logged in user. In this case, you can use a singular resource
  535
+      # to map /profile (rather than /profile/:id) to the show action.
  536
+      #
  537
+      #  resource :profile
  538
+      #
  539
+      # It's common to have resources that are logically children of other
  540
+      # resources:
  541
+      #
  542
+      #   resources :magazines do
  543
+      #     resources :ads
  544
+      #   end
  545
+      #
  546
+      # You may wish to organize groups of controllers under a namespace. Most
  547
+      # commonly, you might group a number of administrative controllers under
  548
+      # an +admin+ namespace. You would place these controllers under the
  549
+      # app/controllers/admin directory, and you can group them together in your
  550
+      # router:
  551
+      #
  552
+      #   namespace "admin" do
  553
+      #     resources :posts, :comments
  554
+      #   end
  555
+      #
444 556
       module Resources
445 557
         # CANONICAL_ACTIONS holds all actions that does not need a prefix or
446 558
         # a path appended since they fit properly in their scope level.
@@ -549,6 +661,24 @@ def resources_path_names(options)
549 661
           @scope[:path_names].merge!(options)
550 662
         end
551 663
 
  664
+        # Sometimes, you have a resource that clients always look up without
  665
+        # referencing an ID. A common example, /profile always shows the
  666
+        # profile of the currently logged in user. In this case, you can use
  667
+        # a singular resource to map /profile (rather than /profile/:id) to
  668
+        # the show action:
  669
+        #
  670
+        #   resource :geocoder
  671
+        #
  672
+        # creates six different routes in your application, all mapping to
  673
+        # the GeoCoders controller (note that the controller is named after
  674
+        # the plural):
  675
+        #
  676
+        #   GET     /geocoder/new
  677
+        #   POST    /geocoder
  678
+        #   GET     /geocoder
  679
+        #   GET     /geocoder/edit
  680
+        #   PUT     /geocoder
  681
+        #   DELETE  /geocoder
552 682
         def resource(*resources, &block)
553 683
           options = resources.extract_options!
554 684
 
@@ -578,6 +708,22 @@ def resource(*resources, &block)
578 708
           self
579 709
         end
580 710
 
  711
+        # In Rails, a resourceful route provides a mapping between HTTP verbs
  712
+        # and URLs and controller actions. By convention, each action also maps
  713
+        # to particular CRUD operations in a database. A single entry in the
  714
+        # routing file, such as
  715
+        #
  716
+        #   resources :photos
  717
+        #
  718
+        # creates seven different routes in your application, all mapping to
  719
+        # the Photos controller:
  720
+        #
  721
+        #   GET     /photos/new
  722
+        #   POST    /photos
  723
+        #   GET     /photos/:id
  724
+        #   GET     /photos/:id/edit
  725
+        #   PUT     /photos/:id
  726
+        #   DELETE  /photos/:id
581 727
         def resources(*resources, &block)
582 728
           options = resources.extract_options!
583 729
 
@@ -608,6 +754,18 @@ def resources(*resources, &block)
608 754
           self
609 755
         end
610 756
 
  757
+        # To add a route to the collection:
  758
+        #
  759
+        #   resources :photos do
  760
+        #     collection do
  761
+        #       get 'search'
  762
+        #     end
  763
+        #   end
  764
+        #
  765
+        # This will enable Rails to recognize paths such as <tt>/photos/search</tt>
  766
+        # with GET, and route to the search action of PhotosController. It will also
  767
+        # create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
  768
+        # route helpers.
611 769
         def collection
612 770
           unless @scope[:scope_level] == :resources
613 771
             raise ArgumentError, "can't use collection outside resources scope"
@@ -618,6 +776,17 @@ def collection
618 776
           end
619 777
         end
620 778
 
  779
+        # To add a member route, add a member block into the resource block:
  780
+        #
  781
+        #   resources :photos do
  782
+        #     member do
  783
+        #       get 'preview'
  784
+        #     end
  785
+        #   end
  786
+        #
  787
+        # This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
  788
+        # preview action of PhotosController. It will also create the
  789
+        # <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
621 790
         def member
622 791
           unless resource_scope?
623 792
             raise ArgumentError, "can't use member outside resource(s) scope"
2  actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -17,7 +17,7 @@ module Routing
17 17
     #
18 18
     # == Usage within the framework
19 19
     #
20  
-    # Polymorphic URL helpers are used in a number of places throughout the Rails framework:
  20
+    # Polymorphic URL helpers are used in a number of places throughout the \Rails framework:
21 21
     #
22 22
     # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
23 23
     #   <tt>url_for(@article)</tt>;
9  actionpack/lib/action_dispatch/routing/url_for.rb
... ...
@@ -1,6 +1,6 @@
1 1
 module ActionDispatch
2 2
   module Routing
3  
-    # In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
  3
+    # In <tt>config/routes.rb</tt> you define URL-to-controller mappings, but the reverse
4 4
     # is also possible: an URL can be generated from one of your routing definitions.
5 5
     # URL generation functionality is centralized in this module.
6 6
     #
@@ -12,15 +12,14 @@ module Routing
12 12
     #
13 13
     # == URL generation from parameters
14 14
     #
15  
-    # As you may know, some functions - such as ActionController::Base#url_for
  15
+    # As you may know, some functions, such as ActionController::Base#url_for
16 16
     # and ActionView::Helpers::UrlHelper#link_to, can generate URLs given a set
17 17
     # of parameters. For example, you've probably had the chance to write code
18 18
     # like this in one of your views:
19 19
     #
20 20
     #   <%= link_to('Click here', :controller => 'users',
21 21
     #           :action => 'new', :message => 'Welcome!') %>
22  
-    #
23  
-    #   # Generates a link to /users/new?message=Welcome%21
  22
+    #   # => "/users/new?message=Welcome%21"
24 23
     #
25 24
     # link_to, and all other functions that require URL generation functionality,
26 25
     # actually use ActionController::UrlFor under the hood. And in particular,
@@ -61,7 +60,7 @@ module Routing
61 60
     #
62 61
     # UrlFor also allows one to access methods that have been auto-generated from
63 62
     # named routes. For example, suppose that you have a 'users' resource in your
64  
-    # <b>routes.rb</b>:
  63
+    # <tt>config/routes.rb</tt>:
65 64
     #
66 65
     #   resources :users
67 66
     #
10  actionpack/lib/action_dispatch/testing/integration.rb
@@ -115,8 +115,8 @@ def delete_via_redirect(path, parameters = nil, headers = nil)
115 115
       end
116 116
     end
117 117
 
118  
-    # An integration Session instance represents a set of requests and responses
119  
-    # performed sequentially by some virtual user. Because you can instantiate
  118
+    # An instance of this class represents a set of requests and responses
  119
+    # performed sequentially by a test process. Because you can instantiate
120 120
     # multiple sessions and run them side-by-side, you can also mimic (to some
121 121
     # limited extent) multiple simultaneous users interacting with your system.
122 122
     #
@@ -373,12 +373,12 @@ def method_missing(sym, *args, &block)
373 373
     end
374 374
   end
375 375
 
376  
-  # An IntegrationTest is one that spans multiple controllers and actions,
  376
+  # An test that spans multiple controllers and actions,
377 377
   # tying them all together to ensure they work together as expected. It tests
378 378
   # more completely than either unit or functional tests do, exercising the
379 379
   # entire stack, from the dispatcher to the database.
380 380
   #
381  
-  # At its simplest, you simply extend IntegrationTest and write your tests
  381
+  # At its simplest, you simply extend <tt>IntegrationTest</tt> and write your tests
382 382
   # using the get/post methods:
383 383
   #
384 384
   #   require "test_helper"
@@ -403,7 +403,7 @@ def method_missing(sym, *args, &block)
403 403
   # However, you can also have multiple session instances open per test, and
404 404
   # even extend those instances with assertions and methods to create a very
405 405
   # powerful testing DSL that is specific for your application. You can even
406  
-  # reference any named routes you happen to have defined!
  406
+  # reference any named routes you happen to have defined.
407 407
   #
408 408
   #   require "test_helper"
409 409
   #

0 notes on commit e8d2002

Please sign in to comment.
Something went wrong with that request. Please try again.