Professional Documents
Culture Documents
• Singular Resources
• Nested Resources
3. Non-Resourceful Routes
• Bound Parameters
• Dynamic Segments
• Static Segments
• Defining Defaults
• Naming Routes
• Segment Constraints
• Request-Based Constraints
• Advanced Constraints
• Route Globbing
• Redirection
• Using root
• Specifying Constraints
• Translated Paths
• Testing Routes
6. Changelog
1 The Purpose of the Rails Router
The Rails router recognizes URLs and dispatches them to a controllerʼs
action. It can also generate paths and URLs, avoiding the need to hardcode
strings in your views.
GET
/patients/17
it asks the router to match it to a controller action. If the first matching route is
@patient
=
Patient.find(17)
<%=
link_to
"Patient
Record",
patient_path(@patient)
%>
The router will generate the path /patients/17. This reduces the
brittleness of your view and makes your code easier to understand. Note that
the id does not need to be specified in the route helper.
DELETE
/photos/17
it asks the router to map it to a controller action. If the first matching route is
resources
:photos
Rails would dispatch that request to the destroy method on the photos
controller with { :id => “17” } in params.
resources
:photos
creates seven different routes in your application, all mapping to the Photos
controller:
Verb
Path
action
used for
GET
/photos
index
display a list of all photos
GET
/photos/new
new
return an HTML form for creating a new photo
POST
/photos
create
create a new photo
GET
/photos/:id
show
display a specific photo
GET
/photos/:id/edit
edit
return an HTML form for editing a photo
PUT
/photos/:id
update
update a specific photo
DELETE
/photos/:id
destroy
delete a specific photo
2.3 Paths and URLs
Creating a resourceful route will also expose a number of helpers to the
controllers in your application. In the case of resources :photos:
resources
:photos
resources
:books
resources
:videos
2.5 Singular Resources
Sometimes, you have a resource that clients always look up without
referencing an ID. For example, you would like /profile to always show
the profile of the currently logged in user. In this case, you can use a singular
resource to map /profile (rather than /profile/:id) to the showaction.
resource
:geocoder
creates six different routes in your application, all mapping to the Geocoders
controller:
Verb
Path
action
used for
GET
/geocoder/new
new
return an HTML form for creating the geocoder
POST
/geocoder
create
create the new geocoder
GET
/geocoder
show
display the one and only geocoder resource
GET
/geocoder/edit
edit
return an HTML form for editing the geocoder
PUT
/geocoder
update
update the one and only geocoder resource
DELETE
/geocoder
destroy
delete the geocoder resource
Because you might want to use the same controller for a singular route (/
account) and a plural route (/accounts/45), singular resources map to
plural controllers.
Verb
Path
action
helper
GET
/admin/posts
index
admin_posts_path
GET
/admin/posts/new
new
new_admin_posts_path
POST
/admin/posts
create
admin_posts_path
GET
/admin/posts/1
show
admin_post_path(id)
GET
/admin/posts/1/edit
edit
edit_admin_post_path(id)
PUT
/admin/posts/1
update
admin_post_path(id)
DELETE
/admin/posts/1
destroy
admin_post_path(id)
If you want to route /posts (without the prefix /admin) to
Admin::PostsController, you could use
Verb
Path
action
helper
GET
/admin/posts
index
posts_path
GET
/admin/posts/new
new
posts_path
POST
/admin/posts
create
posts_path
GET
/admin/posts/1
show
post_path(id)
GET
/admin/posts/1/edit
edit
edit_post_path(id)
PUT
/admin/posts/1
update
post_path(id)
DELETE
/admin/posts/1
destroy
post_path(id)
2.7 Nested Resources
Itʼs common to have resources that are logically children of other resources.
For example, suppose your application includes these models:
Verb
Path
action
used for
GET
/magazines/1/ads
index
display a list of all ads for a specific magazine
GET
/magazines/1/ads/new
new
return an HTML form for creating a new ad belonging to a specific magazine
POST
/magazines/1/ads
create
create a new ad belonging to a specific magazine
GET
/magazines/1/ads/1
show
display a specific ad belonging to a specific magazine
GET
/magazines/1/ads/1/edit
edit
return an HTML form for editing an ad belonging to a specific magazine
PUT
/magazines/1/ads/1
update
update a specific ad belonging to a specific magazine
DELETE
/magazines/1/ads/1
destroy
delete a specific ad belonging to a specific magazine
This will also create routing helpers such as magazine_ads_url and
edit_magazine_ad_path. These helpers take an instance of Magazine as
the first parameter (magazine_ads_url(@magazine)).
You can nest resources within other nested resources if you like. For
example:
/publishers/1/magazines/2/photos/3
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
by Jamis Buck proposes a rule of thumb for good Rails design:
To add a member route, just add a member block into the resource block:
Within the block of member routes, each route name specifies the HTTP verb
that it will recognize. You can use get, put, post, or delete here. If you
donʼt have multiple member routes, you can also pass :on to a route,
eliminating the block:
If you find yourself adding many extra actions to a resourceful route, itʼs time
to stop and ask yourself whether youʼre disguising the presence of another
resource.
3 Non-Resourceful Routes
In addition to resource routing, Rails has powerful support for routing arbitrary
URLs to actions. Here, you donʼt get groups of routes automatically
generated by resourceful routing. Instead, you set up each route within your
application separately.
While you should usually use resourceful routing, there are still many places
where the simpler routing is more appropriate. Thereʼs no need to try to
shoehorn every last piece of your application into a resourceful framework if
thatʼs not a good fit.
In particular, simple routing makes it very easy to map legacy URLs to new
Rails actions.
match
':controller(/:action(/:id))'
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 thePhotosController, and to make the
final parameter "1" available as params[:id]. This route will also route the
incoming request of /photos to PhotosController#index,
since :action and:id are optional parameters, denoted by parentheses.
match
':controller/:action/:id/:user_id'
An incoming path of /photos/show/1/2 will be dispatched to the show
action of thePhotosController. params[:id] will be "1", and params
[:user_id] will be "2".
match
':controller/:action/:id/with_user/:user_id'
This route would respond to paths such as /photos/show/1/with_user/
2. In this case, paramswould be { :controller =>
“photos”, :action => “show”, :id => “1”, :user_id =>
“2” }.
match
':controller/:action/:id'
An incoming path of /photos/show/1?user_id=2 will be dispatched to
the show action of thePhotos controller. params will be { :controller
=> “photos”, :action => “show”, :id => “1”, :user_id =>
“2” }.
You can also define other defaults in a route by supplying a hash for
the :defaults option. This even applies to parameters that you do not
specify as dynamic segments. For example:
get
'photos/show'
You can also permit more than one verb to a single route:
For example, the following routes would allow for posts with to_param
values like 1-hello-worldthat always begin with a number and users with
to_param values like david that never begin with a number to share the
root namespace:
You specify a request-based constraint the same way that you specify a
segment constraint:
class
BlacklistConstraint
def
initialize
@ips
=
Blacklist.retrieve_ips
end
def
matches?(request)
@ips.include?(request.remote_ip)
end
end
TwitterClone::Application.routes.draw
do
match
"*path"
=>
"blacklist#index",
:constraints
=>
BlacklistConstraint.new
end
3.11 Route Globbing
Route globbing is a way to specify that a particular parameter should be
matched to all the remaining parts of a route. For example
Techincally a route can have even more than one wildard segment indeed,
the matcher assigns segments to parameters in an intuitive way. For instance
3.12 Redirection
You can redirect any path to another path using the redirect helper in your
router:
Verb
Path
action
GET
/photos
index
GET
/photos/new
new
POST
/photos
create
GET
/photos/1
show
GET
/photos/1/edit
edit
PUT
/photos/1
update
DELETE
/photos/1
destroy
Use photos_path, new_photos_path, etc. to generate paths for this
resource.
HTTP verb
Path
action
named helper
GET
/photos
index
images_path
GET
/photos/new
new
new_image_path
POST
/photos
create
images_path
GET
/photos/1
show
image_path
GET
/photos/1/edit
edit
edit_image_path
PUT
/photos/1
update
image_path
DELETE
/photos/1
destroy
image_path
4.4 Overriding the new and edit Segments
The :path_names option lets you override the automatically-generated
“new” and “edit” segments in paths:
/photos/make
/photos/1/change
The actual action names arenʼt changed by this option. The two paths shown
would still route to the new and edit actions.
If you find yourself wanting to change this option uniformly for all of your
routes, you can use a scope:
The :except option specifies a route or list of routes that Rails should not
create:
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.
HTTP verb
Path
action
GET
/kategorien
index
GET
/kategorien/neu
new
POST
/kategorien
create
GET
/kategorien/1
show
GET
/kategorien/:id/bearbeiten
edit
PUT
/kategorien/1
update
DELETE
/kategorien/1
destroy
4.8 Overriding the Singular Form
If you want to define the singular form of a resource, you should add
additional rules to theInflector.
• assert_generates
• assert_recognizes
• assert_routing
5.2.1 The assert_generates Assertion
6 Changelog
Lighthouse ticket