wiki:RoutesIntegration
Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Using Routes with TurboGears

 Routes is a Python re-implementation of the  Rails routes system for mapping URL's to Controllers/Actions? and generating URL's. Routes makes it easy to create pretty and concise URL's that are RESTful with little effort.

This is a preliminary integration of routes which is implimented on an app by app basis. No magical discovery of controllers is available yet, but I plan on implimenting this in the near future.

Installing Routes

Installing routes is extremely simple:

easy_install routes

The usual caveats regarding sudo and --script-dir apply

The root controller

Your root controller will need to look like this:

class Root(controllers.RootController):
    
    def __init__(self):
        self.base_re = re.compile( r'^(?P<protocol>[a-zA-Z]+)://(?P<host>.*)' )
        
        # Change the controllers here to the controllers in your app:
        self.controllers = {'pickup': Pickup(), 'main': Main()}
        
        # Here you need to add your own routes (http://routes.groovie.org/manual.html)
        m.connect(':controller/:action', controller='main', action='index')
        m.connect('pickup/:id/:action', controller='pickup', action='prepare', requirements=dict(id='\d{1,11}'))
        
        m.create_regs(self.controllers.keys())
        
    def redirect(self, url):
        # Recreated this function as the cherrypy one is depreciated
        raise cherrypy.HTTPRedirect(turbogears.url(url), 302)
    
    
    @turbogears.expose()
    def default(self, *args, **kwargs):

        base = cherrypy.request.base
        d = self.base_re.match( base ).groupdict()
        host = d[ 'host' ]
        proto = d[ 'protocol' ]
        path = cherrypy.request.path

        con = request_config()
        con.mapper = m # the Routes Mapper object
        con.host = host
        con.protocol = proto
        con.redirect = self.redirect
        con.mapper_dict = m.match( path )

        if con.mapper_dict:
            c = con.mapper_dict.pop( 'controller' )
            controller = self.controllers[c]
            action = con.mapper_dict.pop( 'action', 'index' )
            try:
                meth = getattr(controller, action, getattr(controller, 'default'))
            except AttributeError:
                raise cherrypy.NotFound( path )
            kwargs.update( con.mapper_dict )
            
            return meth( **kwargs )

        raise cherrypy.NotFound( path )

You will also need to add the follwing lines to the top of your controllers.py:

from routes import *
import re
import cherrypy
# Create the mapper object
m = Mapper()

Note that you don't need to connect your controllers to the root controller as you would usually do. The connection of the required controller is done on an ad hoc basis.

I hope to update this using a subclassable RoutesController? (which itself will be a subclass of RootController?) and a few other bits in the TG internals that will allow you to enable and define routes in the .cfg files.