ActionPack / Routing
From WhyNotWiki
http://manuals.rubyonrails.com/read/book/9 Routing: Native Ruby Rewriting |
http://wiki.rubyonrails.org/rails/pages/Routes
‘Routing’ is a pure-Ruby mod_rewrite-alike that can map URLs to controller/action/params and back. It was added to Rails to make pretty URLs more configurable and to divorce us from the mod_rewrite requirement.
Routes are individual rules that map matching URLs to specific controllers and actions. They are configured in the
config/routes.rbfile.
Contents |
[edit] Implicit routes
http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes
map.connect ":controller/:action/:id"That’s an implicit route, because it implicitly maps any number of paths to any number of controllers and actions.
[edit] Named, explicit routes
http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes
map.connect "/people/:id", :controller => "people", :action => "show"The controller and action are now hardwired into the route. And if you’ve gone that far, you might as well go with a named route, too, since you can then access it directly:
map.person "/people/:id", :controller => "people", :action => "show"
Advantages:
http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes
- Route generation using implicit routes is ugly, both internally and externally. I mean, seriously, who wants to type
“link_to(person.name, :controller => ‘person’, :action => ‘show’, :id => person)”when they can type“link_to(person.name, person_url(person))”. [...]- You can use named routes in functional and integration tests. Pretty cool! In functional tests, you can do
“assert_redirected_to(person_url(people(:bob)))”. In integration tests, you can say“get person_url(people(:bob))”. This hearkens back to the refactoring issue—if you change where your actions are, your integration tests remain unaffected.
Pretty
Floyd on http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes:
So called pretty URLs are nearly industry standard fare in the specs I’ve seen recently. Named routes let you do this easily:
map.login "login", :controller => "sessions", :action => "new" link_to "Login!", login_url
Shortcuts/examples:
http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes
If you use Object#with_options, it collapses nicely:
map.with_options :controller => "people" do |people| people.people "/people", :action => "index" people.person "/people/:id", :action => "show" end
See ActiveSupport#with_options.
[edit] RESTful routing
http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes
Eric:
Is the next evolution in routing going to be automatic creation of the “controller_url” helpers for you with only a default implicit route?
Jamis:
That’s what “map.resources” is all about. It puts a convention around all of the above.
But even for the places where it falls apart (like some oddball controller that isn’t RESTful), I think it’s better to be explicit than not.
Eric:
The thing that struck me was when you mentioned routes as being aliases to your actions—which I think is true, but made me think of the Java world that was shunned for all of its numerous layers of indirection.
I don’t mean to say it isn’t useful, or even that it shouldn’t be used, but it is intriguing to see that even in rails there are places where indirection and explicit configurations are both helpful.
Jamis:
Note that indirection (in moderation) is not a bad thing—it’s a crucial part of building any software. Java has just made so many best-practices so hard to do that they taste bad merely by association.
And you have a very good point, Eric: the default, implicit route is a great pedagogical aid, since it allows newcomers to Rails to get up and moving without having to learn anything about routing. [...]
Floyd on http://weblog.jamisbuck.org/2007/1/22/named-explicit-routes:
Named routes are sanctified as convention in 1.2 as ‘paths’. Namely, map.resource :people gets you a whole slew of pretty things like new_person_path. See the recent announcements on the Rails weblog etc.
These are very pretty, but traditional named routes will continue to be relevant because of the things Jamis says above.
[edit] Examples
http://trac.typosphere.org/browser/trunk/config/routes.rb?format=txt
# default
map.index '', :controller => 'articles', :action => 'index'
map.admin 'admin', :controller => 'admin/general', :action => 'index'
# admin/comments controller needs parent article id
map.connect 'admin/comments/article/:article_id/:action/:id',
:controller => 'admin/comments', :action => nil, :id => nil
map.connect 'admin/trackbacks/article/:article_id/:action/:id',
:controller => 'admin/trackbacks', :action => nil, :id => nil
map.connect 'admin/content/:action/:id', :controller => 'admin/content'
# make rss feed urls pretty and let them end in .xml
# this improves caches_page because now apache and webrick will send out the
# cached feeds with the correct xml mime type.
map.xml 'xml/itunes/feed.xml', :controller => 'xml', :action => 'itunes'
map.xml 'xml/articlerss/:id/feed.xml', :controller => 'xml', :action => 'articlerss'
map.xml 'xml/commentrss/feed.xml', :controller => 'xml', :action => 'commentrss'
map.xml 'xml/trackbackrss/feed.xml', :controller => 'xml', :action => 'trackbackrss'
map.xml 'xml/:format/feed.xml', :controller => 'xml', :action => 'feed', :type => 'feed'
map.xml 'xml/:format/:type/feed.xml', :controller => 'xml', :action => 'feed'
map.xml 'xml/:format/:type/:id/feed.xml', :controller => 'xml', :action => 'feed'
map.xml 'xml/rss', :controller => 'xml', :action => 'feed', :type => 'feed', :format => 'rss'
map.xml 'sitemap.xml', :controller => 'xml', :action => 'feed', :format => 'googlesitemap', :type => 'sitemap'
# allow neat perma urls
map.connect 'articles',
:controller => 'articles', :action => 'index'
map.connect 'articles/page/:page',
:controller => 'articles', :action => 'index',
:page => /\d+/
map.connect 'articles/:year/:month/:day',
:controller => 'articles', :action => 'find_by_date',
:year => /\d{4}/, :month => /\d{1,2}/, :day => /\d{1,2}/
map.connect 'articles/:year/:month',
:controller => 'articles', :action => 'find_by_date',
:year => /\d{4}/, :month => /\d{1,2}/
map.connect 'articles/:year',
:controller => 'articles', :action => 'find_by_date',
:year => /\d{4}/
map.connect 'articles/:year/:month/:day/page/:page',
:controller => 'articles', :action => 'find_by_date',
:year => /\d{4}/, :month => /\d{1,2}/, :day => /\d{1,2}/, :page => /\d+/
map.connect 'articles/:year/:month/page/:page',
:controller => 'articles', :action => 'find_by_date',
:year => /\d{4}/, :month => /\d{1,2}/, :page => /\d+/
map.connect 'articles/:year/page/:page',
:controller => 'articles', :action => 'find_by_date',
:year => /\d{4}/, :page => /\d+/
map.connect 'articles/:year/:month/:day/:title',
:controller => 'articles', :action => 'permalink',
:year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
map.connect 'articles/category/:id',
:controller => 'articles', :action => 'category'
map.connect 'articles/category/:id/page/:page',
:controller => 'articles', :action => 'category',
:page => /\d+/
map.connect 'articles/tag/:id',
:controller => 'articles', :action => 'tag'
map.connect 'articles/tag/:id/page/:page',
:controller => 'articles', :action => 'tag',
:page => /\d+/
map.connect 'pages/*name',:controller => 'articles', :action => 'view_page'
map.connect 'stylesheets/theme/:filename',
:controller => 'theme', :action => 'stylesheets', :filename => /.*/
map.connect 'javascripts/theme/:filename',
:controller => 'theme', :action => 'javascript', :filename => /.*/
map.connect 'images/theme/:filename',
:controller => 'theme', :action => 'images', :filename => /.*/
# For the tests
map.connect 'theme/static_view_test', :controller => 'theme', :action => 'static_view_test'
map.connect 'plugins/filters/:filter/:public_action',
:controller => 'textfilter', :action => 'public_action'
# Stats plugin
map.connect '/stats/:action', :controller => 'sitealizer'
# Work around the Bad URI bug
%w{ accounts articles backend files live sidebar textfilter xml }.each do |i|
map.connect "#{i}", :controller => "#{i}", :action => 'index'
map.connect "#{i}/:action", :controller => "#{i}"
map.connect "#{i}/:action/:id", :controller => i, :id => nil
end
%w{blacklist cache categories comments content feedback general pages
resources sidebar textfilters themes trackbacks users}.each do |i|
map.connect "/admin/#{i}", :controller => "admin/#{i}", :action => 'index'
map.connect "/admin/#{i}/:action/:id", :controller => "admin/#{i}", :action => nil, :id => nil
end
map.connect ':controller/:action/:id'
map.connect '*from', :controller => 'redirect', :action => 'redirect'
[edit] Full specification
See the tests: http://dev.rubyonrails.org/browser/trunk/actionpack/test/controller/routing_test.rb
[edit] Ideas
(Not part of Rails)
http://dev.rubyonrails.org/attachment/ticket/6760/ticket_6760_dryer_named_routes_with_block.patch
http://dev.rubyonrails.org/ticket/6760
# named route for a brand image
map.brand_image 'images/account/:account_id/brands/:brand_code.:extension', :controller => 'images', :action => 'brands' do |brand|
{:account_id => brand.account_id, :brand_code => brand.code, :extension => brand.logo.extension}
end
# Can use helper to generate a url for a brand image
brand_image_url_for(some_brand)
