How do I get the URL of the current and other pages? ("restful" problems)

Hi,

I have to deal with the problem that under “restful routing” the
simple scheme of redirecting with parameters stored in variables does
not work anymore.

The given problem: Plenty of actions/views in a given application
contain a button to call a special function programmed in a separate
controller, which immediately returns to the page where it came from.

With the old version of Rails this was pretty easy: I just passed the
current controller, action, and id as parameters, and the special
action did a

redirect_to controller, action, id

where controller, action, and id were variables.

Since rails 2.0 that “restful routing” introduced an illogical URL
structure that breaks old functions like link_to and redirect_to.
Unfortunately, the path is now generated with explicit functions of
the pattern
action_model_path(), which makes it really difficult to stitch old and
new scaffolded controllers and view together. Even worse, the URL
cannot be generated dynamically from parameters, you need to now the
name of the function, and thus what you do at the time of program
writing.

I’d prefer to not use that “restful routing” since I do not see any
advantage over the old scheme. I still wonder why this at all had been
taken into rails.

Unfortunately, the scaffolding now produces “restful” views and thus
makes it hard to avoid it.

Thus, I am now looking for a way to generate the URLs for both old-
and new style controllers dynamically. I’m afraid that this is
impossible. A workaround might be to pass the full rails part of the
URL /… as a parameter. How could a function running in a default
layout determine the current URL?

Hadmut wrote:

Hi,

The given problem: Plenty of actions/views in a given application
contain a button to call a special function programmed in a separate
controller, which immediately returns to the page where it came from.

With the old version of Rails this was pretty easy: I just passed the
current controller, action, and id as parameters, and the special
action did a

redirect_to controller, action, id

where controller, action, and id were variables.

request.request_uri is the URI of the current request, as a string.
Save it in the session. Then you can easily redirect_to that session
variable anytime you like.

What if you had more than just :controller/:action/:id? Maybe your
route you want to send them back to is more like this?

:controller/:action/:id/location/:state/:cityname

If you just capture the :controller/:action/:id then you can’t
regenerate the route. But since you dont always know what all the
params are, you could capture the entire params hash. But that would
also capture posted values like the form fields for the model you just
created. You don’t want that stuff present in your redirect.

These are the reasons you want to capture the URI string, and not the
params themselves.

Since rails 2.0 that “restful routing” introduced an illogical URL
structure that breaks old functions like link_to and redirect_to.
Unfortunately, the path is now generated with explicit functions of
the pattern
action_model_path(), which makes it really difficult to stitch old and
new scaffolded controllers and view together. Even worse, the URL
cannot be generated dynamically from parameters, you need to now the
name of the function, and thus what you do at the time of program
writing.

I believe redirect_to, link_to, button_to, etc., still take :controler
=> …, :action => … style arguments. On the off chance I am
mistaken, you can wrap those hashes in a url_for(…) to generate a
string URI for that combination of params.

I’d prefer to not use that “restful routing” since I do not see any
advantage over the old scheme. I still wonder why this at all had been
taken into rails.

Because a world where you create and manage objects in numerous remote
databases through a consistent and simple interface where a “thing” has
a single url, is a powerful concept. It standardizes controller and
view code so you have to think less about it each time you need to
manage new object type. And, if you do it right, it gives you an almost
free API.

Unfortunately, the scaffolding now produces “restful” views and thus
makes it hard to avoid it.

I can definitely see why this would be awkward if you have a lot of
non-restful controllers and you are generating scaffolds from the latest
rails. That wold get inconsistent pretty quick unless you RESTful-ized
your old controllers too.

Thus, I am now looking for a way to generate the URLs for both old-
and new style controllers dynamically. I’m afraid that this is
impossible. A workaround might be to pass the full rails part of the
URL /… as a parameter. How could a function running in a default
layout determine the current URL?

As a little test, I tried this is a view I have:

<%=h url_for(:controller => ‘users’, :action => ‘show’, :id => 1) %>
<%=h link_to ‘Sweet’, :controller => ‘users’ %>

The result:

/users/1
Sweet

This means url_for, and link_to, and probably redirect_to (though I
didn’t check it) will accept a hash it can generate routes from.

If you are not getting the routes you want out of those, then you may
have some issues with ambiguous routes. This happens if you have 2
routes that accept the same requirements. Rails generates a uri for one
route, but you really meant a different route.

This is why named routes are so awesome. Instead of having to reverse
engineer the params hash to figure out the URI, we can explicitly
generate a specific route. This makes it easier when you have a lot of
complex controllers, and it makes your path generation code much
shorter. You don’t need to use the named route generator methods all
the time, and to be fair you wouldnt want to when capturing an arbitrary
URL.

So, make sure you take a good close look at your routes file and make
sure that it’s declaring everything that way you want.

And RESTfulness is a tad wierd at first, but try it out on a new
project, its quite nice when you get your brain around it.