Ruby on Rails
DispatcherRewritingWish

Instead of using mod_rewrite to rewrite the URLs for the Dispatcher, it should be able to take care of this itself using an external rewrite config file. This would cut down on the duplication currently needed to have the same custom rewrite rules for different adapters. It would also enable the WEBrick server to have custom URLs and decrease the dependency on Apache.

So I’d imagine that we could have some cool rewrite file that would start out with something like:


/controller/action/id

Wish status

Thoughts

I think it would be nicer to, instead of using a rewrite rule, use a class variable (eg. listen_urls or something):


def listen_urls
  ["/%1/%2/%controller/%3",
   "/%controller"]
end

The syntax obviously could do with some polishing (it’s probably possible to use regexps), but the idea is that “%1” signifies that that part is variable, and that whatever stands there gets passed as a parameter in @request“urlparams”“1”. — MartenVeldthuis


To me, it makes more sense to have each controller specify which urls it wants to listen to, instead of having a config file. — Anonymous


It’s important to not lose functionality over what is available from \ModRewrite which is a heck of a lot). With \ModRewrite I can set up a rule set that will let through any request to an actual file or directory (to make all static content work), check for predefined utility controller urls (e.g. ^edit, ^destroy, etc), and then pass every thing else along to a controller than knows how to deal with it. That way I can have URLs like /about/mission and /products/jewerly/ruby that are invisibly rewritten as urls that invoke the show action of the content controller. It’s quite a different use than the application-centric URLs of the default rewriting, but it’s doable with \ModRewrite. Just something to keep in mind when thinking about a different way to do things. — Xian

Also rewriting should not require redirection.Xian


I’ve given this some more thought, and here’s what I’ve come up with. I should note however, that this may not be what David wished for to begin with, so perhaps it should be split off to another wish.

Anyway, as a basis, the pre-“rewritten-for-dispatch” (thus possibly rewritten by mod_rewrite for more complex urls) url should be of the following form:

/controller/controllerparams/action/actionparams?querystring#anchor

Wherein controllerparams is a “/” separated list of parameters to be passed along to the initial creation of the controller object. My proposal would be to use a method called initialize_controller for the initialisation (simply initialize can’t be used because the new method calls that automatically (if this behaviour can be overridden, then ofcourse initialize would be preferred)). For now (for the sake of simplicity), let’s assume that non-required parameters are not allowed.

So, before calling the action, ActionController::Base would determine the number of parameters initialize_controller expects, parse there out of the url, and pass them on into a call to initialize_controller. Then, since it knows the amount of parameters expected by initialize_controller, it can still determine where to find the action part of the url.

I would also suggest to use a variation of above procedure for the call to the action. It would need to be slightly different in order to be backwards compatible with the current situation. Meaning: parse the action parameters, put the first one in @request.params["id"]. If the action doesn’t expect any parameters, stop there, otherwise check the number of parameters expected against the number of parsed parameters. If that matches, call the action with the parsed parameters, otherwise perform some sort of error handling.

I’d really like to hear everyone’s opinion on this idea. If it is a useful addition, I’ll implement this.

As an aside, something which would also be useful in this, is some way of delegating control to another controller from the initialize_controller method. That way, to take Basecamp for example, look at the url /clients/xyzcompany/1/log (yes, I cut out the “project” part of that url), you could set up a controller ClientsController, with a initialization:

def initialize_controller(client, project)
  @active_client = Client.find_by_name(client)
  @active_project = Project.find(project)
  delegate
end

Rails would then instantiate a new controller based on the url part which belongs the what was previously assumed to be for the action (so the new to be processed url would be /log - meaning that \LogController would be instantiated, and the index action would be called).
-
MartenVeldthuis

Marten, I think this would be very useful. I can think of a few cases where this could’ve made my life a little easier..
— jsdk