On Aug 31, 2007, at 1:21 PM, Brian Candler wrote:
> On Thu, Aug 30, 2007 at 06:00:28PM -0600, Duane Johnson wrote:
>> [1]http://pastie.textmate.org/92610
>>
>> Let me know if you have any questions.
>
> This is very useful to understand what the new system is capable
> of, thank
> you.
>
> Could you explain if there some efficiency penalty in using the
> defer_to
> syntax? For example,
>
> r.match("/::/users/::").
> to(:controller => "users", :action =>
"[2]", :id => "[1]")
>
> could potentially be rewritten as
>
> r.match("/::/users/::").defer_to {
> {:controller => "users", :action => $2, :id =>
$1}
> }
>
> (I''m not sure $1, $2 etc are actually set at this point, but you
> get the
> idea). Doing it this way would use more standard Ruby notation for
> captures
> than "[1]" and "[2]", which is why I like it.
>
> But does using the to(...) syntax allow you to compile the router
> into a
> faster form?
>
Yes, there is a slight penalty. If you can match without deferring,
your routes will be optimized in a big if/elsif statement. With that
said, however, the deferred block is evaluated AFTER all other
conditions (e.g. only if the "/::/users/::" portion is a match), so
you can get away with this slight performance decrease if you
restrict your deferred matching to specific portions of the site.
With regard to your example above, I think this will work:
r.match("/:action/users/:id").defer_to { |request, params|
# params = {:action => "some_action", :id =>
"some_id"}
params.merge(:controller => "users")
}
I had some questions in IRC recently about the defer_to arguments, so
perhaps I can repeat it here.
The defer_to block takes two arguments, which I prefer to call
"request" and "params". The simplest case of a deferred
route block
is as follows:
r.defer_to { |request, params| params }
It says, "This route is always a match. Return the params hash,
unchanged". You could add conditions, like so:
r.defer_to { |request, params| params if ExternalLibrary.matches? }
In the case where matches? returns true, the params hash will be
returned, and the route will be evaluated as true. In the false
case, the if statement returns nil, the route match thus fails, and
the routes system will continue checking for matches against other
routes down the line.
Here''s a more practical example of a type-agnostic route where we
defer to a block at run-time to determine if the route is a match:
r.match("/object/:id").defer_to(:action => "index") do
|request, params|
thing = GenericObject.find_by_id(params[:id])
if (thing)
params.merge(:controller => thing.controller)
end
end
As of revision 467 (a few minutes ago, as of this writing), the
"params" hashes passed into the deferred blocks above now include the
query_string''s parsed params as well as the placeholders parsed out
of the path. For example:
REQUEST: http://www.mysite.com/object/22392?backdoor=true
# Using the example above...
r.match("/object/:id").defer_to(:action => "index") do
|request, params|
# params ==> {:id => "22392", :backdoor => "true"}
# ...
end
Regards,
Duane Johnson
(canadaduane)
http://blog.inquirylabs.com/