ActionPack / Routing

From WhyNotWiki

Jump to: navigation, search

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.rb file.

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)


ActionPack / Routing  edit   (Category  edit)

Personal tools