Routing Priority and Unknown Action


#1

I have a site that consists of a blend of static and dynamic pages. The
solution I came up with uses the default routing to try to pair up a
controller and action for the dynamic stuff and, if the url doesn’t
jive, rails attempts to render the static content with a special
controller just for rendering that.

To allow the static content to use all sorts of user memorable URLs I
used routing:
map.connect ‘:controller/:action’
map.connect ‘*misc_url’, :controller => ‘static’, :action =>
‘render_content’

Seems graceful enough (though I have to handle 404 page rendering in the
static controller since it gets EVERYTHING).

So assuming I have a controller named “a” with an action named “b” and I
try the URL “/a/b” => all is well.

Then I try “/something/else” => the static controller gets it and deals
with it appropriately.

But then I try “/a/bogus_action” => I get “Unknown Action” Apparently
routing does not ever hand this one off to the Static Controller (where
404 or other appropriate responses reside).

Is this a bug? Is rails really supposed to leave it up to the
controller that doesn’t have a corresponding action? If this is “good”
behavior, is there some kind of workaround that I can mixin to all my
controllers or to routing to so that this ends up being handed to the
Static Controller?


#2

Chris P. wrote:

But then I try “/a/bogus_action” => I get “Unknown Action” Apparently
routing does not ever hand this one off to the Static Controller (where
404 or other appropriate responses reside).

Is this a bug? Is rails really supposed to leave it up to the
controller that doesn’t have a corresponding action? If this is “good”
behavior, is there some kind of workaround that I can mixin to all my
controllers or to routing to so that this ends up being handed to the
Static Controller?

It’s not a bug in Rails - it’s doing exactly what you told it do to. If
you don’t want random actions being routed to your controller, you can
restrict the set of actions in your routing rule by using the
:requirements option (which might be ugly if you have more than a couple
actions), or (my preference) by specifying each action in its own rule.
The #with_options message is a nice way to avoid repeating the
controller in each rule.

map.with_options(:controller => ‘welcome’) do |r|
r.welcome ‘’, :action => ‘index’
r.welcome ‘index’, :action => ‘index’
r.welcome ‘about’, :action => ‘about’
r.welcome ‘login’, :action => ‘login’
end


Josh S.
http://blog.hasmanythrough.com


#3

Josh S. wrote:

you can restrict the set of actions in your routing rule by using the
:requirements option (which might be ugly if you have more than a couple
actions), or (my preference) by specifying each action in its own rule.
The #with_options message is a nice way to avoid repeating the
controller in each rule.

map.with_options(:controller => ‘welcome’) do |r|
r.welcome ‘’, :action => ‘index’
r.welcome ‘index’, :action => ‘index’
r.welcome ‘about’, :action => ‘about’
r.welcome ‘login’, :action => ‘login’
end

Thanks for the reply but that’s a little too tightly coupled for me. I
anticipate quite a few more controllers and as I make changes or
refactor behaviors, I’d be constantly breaking my routing. It’s
important to me to only define what’s unique or different and just have
a few simple rules define the common patterns as much as possible.

On the ah-ha side of things, I have learned that adding a method_missing
action to the application.rb file will allow me to handle any missing
methods in my controllers.

def method_missing(*args)
render_404 # calls my common 404 rendering method
end

So, I’m getting closer to what I need but I would still like to pass
control to the my Static Controller (in case the URL is really referring
to a valid static page and not a 404). Obviously, I can call the Static
Controller’s render_conetent method directly but I need to create the
:misc_url parameter since the routing didn’t do it for me.

Any suggestions on creating this parameter - or better yet, having
routing do it for me somehow to make this solution more future proof?