Hi Eric. You've hit directly upon Routes' fragility. Routes and
WebHelpers were ported directly from Rails, and it took a year of
using them to determine that parts of them were good, parts were
missing, and parts allowed programming practices that didn't scale.
The converse of using ":controller/:action/:id" for everything is to
define highly specific routes for each allowed URL. I prefer the
latter, but it does require writing more routes. So the first issue
is laziness: are people using ":controller/:action/:id" because it
fits their application's structure well, or simply to avoid writing
routes? Of course laziness is a virtue (according to Larry Wall), but
should Routes allow it? I'm not saying yes or no here, just pointing
out the issues and tradeoffs.
One argument is that the preconfigured general route allows newbies to
write simple applications without getting into the details of Routes
right away -- they're already busy learning about controllers and
request and templates. But then, is newbie laziness (and oldbe
laziness) good over the long term, or does it makes the apps harder to
maintain as they get bigger?
On Sat, Mar 8, 2008 at 1:05 PM, Eric Ongerth <[EMAIL PROTECTED]> wrote:
>
> Here's what I want to be able to do with Routes. I do want to be able
> to take advantage of the following cases of minimization, but I want
> to be able to explicitly call controller/action/id when the defaults
> i've set up are not enough. I'm curious how my scenario compares to
> the above discussion. If I was another year deep in Pylons or web-dev
> in general, I'm sure an answer to that question would be more clear to
> me; instead, i'm asking this in order to learn more, if anyone is
> willing to comment.
It's a bit difficult to answer without knowing what your routes are.
I'll have to assume a single ":controller/:action/:id" route, or a few
routes that are slightly more specific. So my answer may leave out
some possibilities I didn't think of. I'll start with how I would
structure it (named routes), and then attempt an alternative that's
closer to your syntax.
> 1. I want to be able to configure "index" as the default action when I
> call url_for and supply a controller, but no action or id. Also,
> since I know it's the default action in this case, the word "index"
> does not need to appear in the URL. So url_for(controller="SomeClass")
> should result in the URL "/SomeClass", which should link to controller
> "SomeClass", action "index".
So say you have several URLs that happen to be "/controller/action",
and you want the action to default to 'index'.
I would use named routes for each:
map.connect("mysection", "mysection", controller="section", action="index")
map.connect("mysection", "mysection/:action", controller="section")
url_for("section") # Main page.
url_for("section", action="the_action") # Another page.
However, I would define a specific route for each action, and use a
multi-URL route only at the 'id' level.
When we drop minimization, you'll have to define a separate route for
your index page, but users will see "/mysection" rather than
"/mysection/index". in fact, "/mysection/index" won't work unless
another route matches it (as the second route above does).
This is not directly related to whether you use named or unnamed
routes, or whether you put the name in the url_for call. But in
Routes 2, nameless routes and calling url_for without a name may have
limited support and work with a single default route, or they may be
disallowed.
Again, you'll be able to stick with Routes 1 even if Pylons default
switches to Routes 2. There are some issues in how this would work
(the dependency version in setup.py, whether you'd have to do
something extra to activate the older Routes version, and whether
reinstalling Pylons would activate the "wrong" version of Routes), but
this is a goal and I'm sure we'll find some way to do it.
> 2. I want to be able to configure "show" as the default action when a
> controller AND an id are given, but no action. And since I know it's
> the default action in this case, the action need not show as a field
> in the visible URL. So url_for(controller="SomeClass", id="16384")
> should result in the URL "/SomeClass/16384", which should link to
> controller "SomeClass", action "show", id "16384".
'id' will no longer be treated specially; it's just another variable.
Dropping the action can be done with another route, but not combined
in the same route.
NUMERIC = r"^\d+$"
map.connect("critter", "/critters/:id", controller="critters", action="show",
_requirements={"id": NUMERIC})
map.connect("critter_control", "/critters/:action/:id", controller="critters")
url_for("critter", id=3)
url_for("critter_control", action="foo", id=3)
As you can see I couldn't think up a good name for the second route.
But since I would use a separate route for each action, that issue
doesn't come up for me. If you want to make these routes more
general, you could replace 'critters' with ':controller'.
The numeric requirement is sometimes required to prevent a route from
matching a URL intended for another route. In this case it's not
strictly necessary because there's no URL that could match both
routes. That is, WITHOUT minimization. With minimization the second
route could match "/critters/3" -- oops. That's why it's AFTER the
first route in Routes 1.
But if you inserted a second route:
map.connect("critter_help", "/critters/help",
controller="helpapplication", action="critters")
and removed the numeric requirement in the first route, the first
route would match "/critters/help" -- oops!
Using unnamed routes, you'd be subject to variable matching, which may
or may not do what you intend after some trial and error.
Also, I can't guarantee that Routes 1 will choose the correct route
even url_for provides a name, because variable matching overrides
names. That's another reason I want to get a Routes 2 alpha finished
in the PyCon sprint.
> 3. When other actions are needed (i.e. create, update, delete, etc.)
> I'll supply controller, action, and id all to url_for and accept the
> fact that all three fields need to shown in the URL.
Well, this overlaps with map.resource, which provides those. (Your
'show' method also suggests you're doing some resource-like thing.
map.resource works but it has very specific ideas about what URLs
should be. I'm working on some alternative resources that would be
more flexible.
If you're not using a multiple-route creator like map.resource, I'd
suggest defining specific routes for each of these actions. That may
avoid some ambiguities which might arise with using more general
routes.
> As a result of that seemingly fragile state of affairs, I have given
> up on the minimization/defaults techniques that I had really hoped to
> employ. Instead I've resorted to spelling out the controller and
> action for every request. Of course that works fine, but the URLs of
> course show information that I consider redundant or superfluous (such
> as when the URL mentions a controller but no id, and therefore should
> not have to explicitly mention the action "index" since index is the
> only consistent action when no id is present).
Your "route for every request" sounds almost like my "route for every
action", but a request is more specific than an action. Extra
variables at the end of the URL, and/or query parameters, can make the
route usable for different URLs to the same action. Variables can be
used not only to choose an ID but to put the action into different
modes.
The URLs do NOT have to show the controller and action, and security
suggests they shouldn't. That's one reason ":controller/:action"
gives me the creeks -- you can accidentally expose a method that
wasn't intended to be an action, or a former action you forgot to
delete.
--
Mike Orr <[EMAIL PROTECTED]>
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"pylons-discuss" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en
-~----------~----~----~----~------~----~------~--~---