Politics, Programming and Possibilities
27 Aug
Note: The API has significantly changed since this posting. Best to check out this post for details.
With Ezra’s approval, I committed some significant changes to the Merb routing system last night. If you’ve ever been limited by Rails’ routing system, you might want to check out some of the features now in Merb. Here’s a run-down of some ways you can use the new system:
Merb::Router.prepare do |r|
# There is now a named_route method which is
# basically a simple_route plus a URL generator
r.named_route :test,
"/:controller/:action/:id/:prefix",
:action => ':prefix_:action'
end
# In a controller or view, we can use its generator:
url :test,
:controller => "users",
:action => "show",
:id => 1,
:prefix => "alternate"
# => "/users/show/1/alternate
# Example controller class that would respond properly:
class Users < Application
def simple_show
#
end
def alternate_show
#
end
end
Merb::Router.prepare do |r|
# Send all SSL / HTTPS traffic to the Secure class, 'index' action
r.route :protocol => /https/,
:controller => "secure",
:action => "index"
# Use the 'admin' subdomain to route to the admin module
r.route :domain => /^admin\\./,
:path => %r[/~~/~~/~~],
:controller => “admin/:path[1]“,
:action => “:path[2]“,
:id => “:path[3]”
end
Note in the above example that some of the keys in the hash are environment variables (:domain, :path) and some are outputs to the params hash (:controller, :action, :id). This may change in the future, but for now it just means you have to know that the environment variables are “reserved words”, used specifically for matching against the incoming URL request.
Also, you may wonder at the “~~” and “:path[1]” notation. The “~~” in the path is a special string sequence that gets replaced with a parenthetical regular expression that will match a normal URL segment (e.g. it will match characters such as a-z but not ‘/’ or ‘?’). Next, the “:path[1]” notation is used to tell the router how to reconstruct the params from the matched portions of the request / environment variables. So, in the above example, the :controller is going to be “admin/” plus whatever gets matched in the first “~~”. Here’s an example match. Let’s use the URL, “http://admin.mysite.com/books/show/1″:
# Routes to the controller Admin::Books, and the "show" action
module Admin
class Books < Application
def show
params[:controller] # => “admin/books”
params[:action] # => “show”
params[:id] # => “1″
end
end
end
A full list of request / environment variables that you can use is available in the lib/merb/router.rb class, but here is a sampling:
This flexibility could, for example, let you essentially create two different sets of views for Mozilla vs. Internet Explorer browsers (routes would distinguish between browsers using the “user_agent” variable). Or you could ban certain IP addresses. Or allow certain routes from third party sites using the “referer”. Lots of possibilities.
Merb::Router.prepare do |r|
# Query the database for an object type, and then route
# to the appropriate controller based on type
r.route do |request|
if request.path.match(%r{/([a-z0-9\-] )})
guid = $1
if obj = AppObject.find_by_guid(guid)
{:controller => obj.type, :action => ’show’, :id => guid}
end
end
end
end
Some things may continue to change as I get feedback and also optimize the system, but the above examples should stand as a doorway for solutions to your own development needs. Let me know if you have any special requests and I’ll try to post more later.
4 Responses for "New Router in Merb"
This is really nice, Duane. I’m especially excited about playing with late bound routes. Great stuff!
Yeah, very sweet stuff Duane.
You probably want to escape the period in
/^admin./.Henrik: Indeed, you’re right. I’ll switch it.
Leave a reply