I'm not a traversal expert but here's my 2c.
Traversal has a small niche where it's significantly better than URL
Dispatch, and a much larger niche where either Traversal or URL
Dispatch are equally effective but they lead to different code
organization.
The case where Traversal is significantly better is when you don't
know beforehand which object types will be at which URLs, especially
when users are allowed to create a tree structure rather than a flat
namespace. Content management systems are the quntessential example of
this.
However, many applications have a fixed URL structure, and a class
management system may be one of those. You said your URLs are like
"/classes/{class_id}/students/{student_id}". In that case, Traversal
vs URL Dispatch is mostly a preference choice. The advantage is that
the dispatcher will look up the resource for you and present it as the
"context", with parents. Otherwise you'd have to look those up
yourself in the view. How much difference does it make? Not much, just
using "context" vs another variable.
And you have to create a resource tree, which wouldn't be necessary
without Traversal. This adds a certain amount of work, so the question
is, how much unique benefit can you add at the same time? It gives the
opportunity to move some of the code in (URL Dispatch) views into the
resource and its parents, as methods or attributes. In other words, in
ordinary (URL Dispatch) model objects, you have your column
attributes, and you may also have some methods and non-persistent
attributes. In Traversal, you can add additional methods and
attributes beyond that to the context and its parents, things that
leverage the Traversal structure and lead to better organized code,
maybe. That "maybe" is important, because is it really better
organized, or are you trying to shoehorn things into the
resource/parent structure that don't really belong?
There hasn't been much written about what kinds of things are worth
pushing into the resource structure in a fixed-URL application, so I
don't really have an answer. Sometimes I think about putting index
wrappers; e.g., where "/articles" is an index page for "/articles/X".
In that case, I don't need the full child objects, but just enough
fields to generate the index page and do searches and the like. So
should I make the index result list (or a paginator of it) into the
"context" of the index view? But what have I gained? It's just moving
a query from one place to another. Whether it's called "context" or
not is perhaps unimportant. And when I go through the parent to a
child context, I don't want the parent generating a superfluous query
I'll never use.
Similar issues come up in building up breadcrumbs links or
neighbor-navigation links. If the parent generates a query just by
traversing it, then you're continually having root queries and section
queries on every request. And to get that list of neighbor-links
(siblings, etc), you'd have to go far and wide through the resource
tree on every request, and if you naively make it fetch all these
other nodes entirely rather than using a limited index query, you end
up fetching a whole lot of stuff you won't use in that request. So
these things *can* be done via the resource tree, but it's not
necessarily always the ideal way.
Another issue is generating URLs to other nodes. It's easy to generate
the context's URL or an ancestor's. But what about another node? Is it
really worth fetching that object through the tree and asking it its
URL? Or is it OK to just hardcode the URL down from a resource you
already know (the root or an ancestor); e.g.,
'request.resoufce_path(root, "other_view")' or
'request.resource_path(root, "other_section", "other_view")'. I used
to avoid that as improperly hardcoding names, but now I'm starting to
wonder, because the method *does* seem to explicitly have that
capability.
Anyway, those are my current thoughts about traversal.