This project is archived and is in readonly mode.

#4444 new
Luigi Montanez

Can no longer rescue_from ActionController::RoutingError

Reported by Luigi Montanez | April 20th, 2010 @ 04:50 PM | in 3.1

In Rails 2.3.x, one is able to stick this in ApplicationController to present the user with a custom 404 screen:

rescue_from(ActionController::RoutingError) { render :text => 'This is a custom 404.' }

Now in Rails 3, because routing is done as middleware (ActionDispatch), it seems that the ActionController::RoutingError that gets thrown by ActionDispatch no longer can be caught from ApplicationController -- the error is already thrown and ActionDispatch renders /templates/rescues/routing_error.erb before the controller can rescue_from the error.

Comments and changes to this ticket

  • Ben Marini

    Ben Marini April 27th, 2010 @ 03:38 AM

    I verified this with a freshly generated rails app from the master branch. I haven't investigated too far, but at this point the best way I can see to do this in rails 3 is to subclass and swap out the ActionDispatch::ShowExceptions middleware. Or add a route that matches anything...is there a better way?

  • Jean

    Jean May 27th, 2010 @ 09:09 PM

    • Tag changed from rails3 routes, 3.0.0.beta3 to rails3 routes, 3.0.0.beta3, rails3, rescue, routes, routingerror

    I am also hitting this problem, but my understanding of the internals of rails3 is very limited atm ...

    Couldn't we define the rescue handling as an option to the route ? (thus in route.rb)

  • Neeraj Singh

    Neeraj Singh May 28th, 2010 @ 04:35 AM

    Put following code in an initializer in a rails3 app.

    module ActionDispatch
      class ShowExceptions
        def render_exception(env, exception)
          if exception.kind_of? ActionController::RoutingError
            render(500, 'it was routing error')
          else
            render(500, "some other error")
          end
        end
      end
    end
    

    There might be a better way but it works in my quick test.

  • José Valim

    José Valim July 13th, 2010 @ 08:58 PM

    • Milestone set to 3.1
    • Assigned user set to “José Valim”
    • Importance changed from “” to “Low”

    The best way to handle a missing route in Rails 3 is by adding the following line at the end of your router:

    match "*", :to => "home#routing_error"

    And add the routing_error action. We will be working on a better solution, but it is targeted for 3.1.

  • Hubert Łępicki

    Hubert Łępicki July 25th, 2010 @ 05:47 PM

    José, are you sure that your solution actually works? I think it's not working as you can't simply say match "*" to match everything in Rails 3 so far?

  • Hubert Łępicki

    Hubert Łępicki July 25th, 2010 @ 05:52 PM

    I mean, you have to do it like this:

    match '/:anything', :to => "home#routing_error", :constraints => { :anything => /.*/ }

  • Hubert Łępicki

    Hubert Łępicki July 26th, 2010 @ 08:14 AM

    I was giving it a bit more thought since yesterday. The solution with match "/:anything" is also not perfect for some people, as it'll override all routes from plugins/engines. I now think that best solution is to use custom rack middleware for handling 404 pages in Rails.

  • Matthew Gibbons

    Matthew Gibbons August 13th, 2010 @ 03:14 PM

    The approach that I have adopted to solve this (for now) is to make a call back into the application (from ActionDispatch::ShowExcpetions#render_exception), specifically to a controller that is there for the purpose of rendering an error page. This has all the benefits of using the layout and styling of the host application. However, if a second exception occurs whilst handling the exception in this way, the original method is called, and the default is rendered.

    It is better explained here: http://accuser.cc/posts/1-rails-3-0-exception-handling

    For those who would rather copy and paste than read the above... ;)

    1. http://gist.github.com/522944
    2. http://gist.github.com/522924
  • Andre Pankratz
  • gucki

    gucki September 22nd, 2010 @ 02:34 PM

    The easiest way for me was to add this very last route:

    match ''=> lambda { |env| raise ActionController::RoutingError, env["PATH_INFO"] }

  • gucki

    gucki September 22nd, 2010 @ 02:51 PM

    Please ignore my previous comment, it does not work that way. Seems rails had some routes cached, so it seemed to work initially.

  • Ryan Bigg

    Ryan Bigg October 9th, 2010 @ 10:00 PM

    • Tag cleared.

    Automatic cleanup of spam.

  • Ryan Bigg

    Ryan Bigg October 19th, 2010 @ 08:22 AM

    Automatic cleanup of spam.

  • Tian Davis

    Tian Davis November 12th, 2010 @ 12:25 AM

    Personally, I'm waiting for an Official solution from the Rails Core Team. Until then I need a simple, no side effect solution for catching rogue routes. For now, my solution is an elaboration on José Valim's recommendation:
    http://techoctave.com/c7/posts/36-rails-3-0-rescue-from-routing-err...

    With this approach, you'll be in unison with the Rails Core Team. Moreover, I incorporate Rails 3 Route Globbing, so you get the added benefit of knowing exactly which rogue route was entered. As a result, you're free to handle routing errors as creatively as you'd like.

  • avocade (at gmail)

    avocade (at gmail) December 19th, 2010 @ 02:50 AM

    Issue for more than just rescuing from routing errors, CanCan::AccessDenied too:

    http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devi...

  • Kevin Watt

    Kevin Watt March 18th, 2011 @ 03:40 PM

    This is a huge bug and I feel it's priority should be raised.

    It's not acceptable for a broken link in a production app to result in a blank screen, this is why we make 404 handlers. But once the request is dispatched to rails it seems to be rails job to render the 404 page, which it can't do because of this bug.

  • Kevin Watt

    Kevin Watt March 18th, 2011 @ 04:56 PM

    Just to add,
    match '/:anything', :to => "home#routing_error", :constraints => { :anything => /./ } or
    match "
    ", :to => "home#routing_error"

    Don't seem to work when the controller exists but the action doesn't. Exception log still just shows "AbstractController::ActionNotFound (The action 'rejsasdf' could not be found for HomeController):" and a blank page is rendered.

  • Andrew White

    Andrew White March 19th, 2011 @ 06:48 AM

    Are you using :action as the dynamic segment name? If so Rails will try to find the action in the controller. The following path works for me:

    match '*path', :to => 'errors#not_found'
    

    This won't catch a missing root path - but I'm guessing you're website is there.

  • Andre Pankratz

    Andre Pankratz March 19th, 2011 @ 08:36 AM

    • Assigned user cleared.

    A catch-all route at the end of your routes my seem like a simple fix, but it has a major drawback:
    If your application relies on engines that extend your app with their own routes, things will break because those routes will never get fired!

    I've published a gem that solves the routing error. It basically catches the exception on Rack-level and re-raises it on application-level: https://github.com/vidibus/vidibus-routing_error

  • Andre Pankratz

    Andre Pankratz March 19th, 2011 @ 08:37 AM

    • Assigned user set to “José Valim”

    Oops, I removed José. Sorry.

  • Kevin Watt

    Kevin Watt March 19th, 2011 @ 02:36 PM

    I am using non-restful routes, which is perhaps why the catch-all doesn't work for me

    match ':controller(/:action(/:id))', :constraints => {:id => /.*/}
    

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Referenced by

Pages