Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can no longer rescue_from ActionController::RoutingError #671

Closed
lighthouse-import opened this issue May 16, 2011 · 58 comments
Closed

Can no longer rescue_from ActionController::RoutingError #671

lighthouse-import opened this issue May 16, 2011 · 58 comments

Comments

@lighthouse-import
Copy link

Imported from Lighthouse. Original ticket at: http://rails.lighthouseapp.com/projects/8994/tickets/4444
Created by Luigi Montanez - 2011-02-14 05:42:01 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Ben Marini - 2010-04-27 02:38:02 UTC

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?

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Jean - 2010-05-27 20:09:31 UTC

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)

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Neeraj Singh - 2010-05-28 03:35:17 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by José Valim - 2010-07-13 19:58:09 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Hubert Łępicki - 2010-07-25 16:47:51 UTC

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?

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Hubert Łępicki - 2010-07-25 16:52:04 UTC

I mean, you have to do it like this:

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

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Hubert Łępicki - 2010-07-26 07:14:54 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Matthew Gibbons - 2010-08-13 14:14:51 UTC

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

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Andre Pankratz - 2010-08-17 17:11:44 UTC

Here is a gem that may solve this issue: http://github.com/vidibus/vidibus-routing_error

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by gucki - 2010-09-22 13:34:45 UTC

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

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

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by gucki - 2010-09-22 13:51:13 UTC

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

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Ryan Bigg - 2010-10-09 21:00:28 UTC

Automatic cleanup of spam.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Ryan Bigg - 2010-10-19 07:22:55 UTC

Automatic cleanup of spam.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Tian Davis - 2010-11-12 00:25:17 UTC

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-error-solution

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by avocade (at gmail) - 2010-12-19 02:50:57 UTC

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

http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Kevin Watt - 2011-03-18 15:40:52 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Kevin Watt - 2011-03-18 16:56:03 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Andrew White - 2011-03-19 06:48:59 UTC

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.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Andre Pankratz - 2011-03-19 08:36:52 UTC

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

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Andre Pankratz - 2011-03-19 08:37:41 UTC

Oops, I removed José. Sorry.

@lighthouse-import
Copy link
Author

Imported from Lighthouse.
Comment by Kevin Watt - 2011-03-19 14:36:35 UTC

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

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

@josevalim
Copy link
Contributor

Yeah, you can no longer do that. You need to define a catch all route.

@webmat
Copy link

webmat commented Jun 1, 2011

Why has this issue been closed? As far as I can tell, Rails 3.1 RC1 still hasn't added back support rescue_from, right?

Or is it going to be in the next RC / official release?

@josevalim
Copy link
Contributor

No Exceptron did not get in Rails 3.1. :( We are going to merge it into master soon.

@rsanheim
Copy link
Contributor

Should this issue be re-opened until the actual fix is merged?

@GAV1N
Copy link

GAV1N commented Jul 10, 2011

Any word on the status of this issue?

@albertoperdomo
Copy link

Can someone please provide some more info on the status of this issue? I'm still seeing it on edge.
Steps to reproduce: https://gist.github.com/1114757

@samuelkadolph
Copy link
Contributor

With how rails 3 was restructured to be a real rack app, it's not longer easy and clean to raise that error inside the context of a controller instance.
The best approach is a catch all route at the end of routes.rb: `get "*" => "home#not_found". You could also route it to an action that would raise the error and then you could handle it with a rescue_from.

@albertoperdomo
Copy link

Ok, I understand it's going to stay this way.
Thanks for clarifying.

@nunziofiore
Copy link

great explanation
Thank you very much
Nunzio Fiore

On Mon, Feb 20, 2012 at 11:40 AM, Reinier de Lange <
reply@reply.github.com

wrote:

It's because your rails app is a rack app as well. Rack calls every
registered app until one handles it. This is what happens when you
redirect. When you don't redirect and respond with 404, the next app in the
chain is called. One of these apps is the omniauth middleware.


Reply to this email directly or view it on GitHub:
#671 (comment)

@canma5
Copy link

canma5 commented Feb 22, 2012

Hello,

I want to handle not only routing errors. I have used the code from #671 (comment) and is working fine.

What I would like to do is to render a page directly instead of displaying a message. Therefore I've replaced --> render(500, 'it was routing error') for this --> render :file => "#{RAILS_ROOT}/public/500.html", :status => 500

But I get an error: wrong number of arguments (1 for 2)

This is what im trying:

module ActionDispatch
class ShowExceptions
def render_exception(env, exception)
if exception.kind_of? ActionController::RoutingError
#render(500, 'it was routing error')
render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
else
#render(500, "some other error")
render :file => "#{RAILS_ROOT}/public/500.html", :status => 500
end
end
end
end

Any help will be very welcome! Thanks in advance!

@moiristo
Copy link

why don't you just use rescue_from for anything other than routing errors?

@canma5
Copy link

canma5 commented Feb 23, 2012

Hi, I thought rescue_from didnt work in Rails 3.0.X versions. Reading now better the post I assume that the only one that doesnt work is for the Routing errors. Sorry, my bad!

@bkimble
Copy link

bkimble commented Mar 28, 2012

@canma5 Correct - rescue_from doesn't work with ActionController::RoutingError in 3.2.0, but does work for everything else.

@jrochkind
Copy link
Contributor

What is the current status?

11 months ago, josé:

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

10 months ago, josé:

No Exceptron did not get in Rails 3.1. :( We are going to merge it into master soon.

Now we're in several patch releases of rails 3.2. Is there any new official way to deal with this? Or is the only way still a catch-all route? The problem with the catch-all route, as others have mentioned, is it messes up engine-supplied routes. To deal with that, you can do it in an after_initialize block or some other initializer you hook in after engine routes are loaded... but this starts getting kind of cumbersome and confusing for the beginner. At one point José suggested Rails core team planned to implement some other fix -- is there still such a plan/desire?

@mattgreen
Copy link

+1 looking forward to a status update.

@spencerfry
Copy link

Any update on how to handle this?

@dmathieu
Copy link
Contributor

This issue shouldn't be closed.

@guilleiguaran guilleiguaran reopened this Apr 24, 2012
@spastorino
Copy link
Contributor

@guilleiguaran
Copy link
Member

Closing, see @spastorino comment

@jrochkind
Copy link
Contributor

I do not understand how to apply @spastorino's comment. Is it possible to rescue from Routing exceptions in current Rails, and if so, how?

@josevalim
Copy link
Contributor

For everyone waiting on a status update, I've written briefly about it here (point 3):

http://blog.plataformatec.com.br/2012/01/my-five-favorite-hidden-features-in-rails-3-2/

@jrochkind
Copy link
Contributor

Thanks. Is rescue_from discouraged/deprecated behavior, and the new middleware-based config.exceptions_app should be used instead? Or just for routing errors?

@robertgrimm
Copy link

Regarding the blog post that josevalim posted, is that the real way to handle this? I like that method and it works well for me except for integration tests that tests for a 404 server response since the ActiveRecord::RecordNotFound exception bubbles up to the tests. I've been able to fix that by doing the 'rescue_from ActiveRecord::RecordNotFound' thing but that seems like duplication since I also have a 'match 404' in my routes.

@phlegx
Copy link

phlegx commented Dec 18, 2014

Here an example: https://gist.github.com/Sujimichi/2349565

sfate added a commit to fameandpartners/website that referenced this issue Jan 14, 2017
sfate added a commit to fameandpartners/website that referenced this issue Jan 14, 2017
sfate added a commit to fameandpartners/website that referenced this issue Jan 16, 2017
sfate added a commit to fameandpartners/website that referenced this issue Feb 5, 2017
sfate added a commit to fameandpartners/website that referenced this issue Feb 17, 2017
sfate pushed a commit to fameandpartners/website that referenced this issue Feb 21, 2017
* 404 page redesign

* Fix css format

* Fix link destination

* Remove old 404 file

* Add new controller and helper

* Add new 404 template

* Add new route to the 404 page

* Tell rails to use tempaltes

* Error pages sass

* Catch errors with custom error pages yielded w/ application layout

* update styling and put content inside .container

* Optimize calls + raise exception for development mode

* Return back static 500 page

* Make rails app available to catch RoutingError (raised by ActionDispatch)

Ref: rails/rails#671

* Fix not found routes spec

* Fix unmactched routes catch

* Fix specs
gus4no pushed a commit to fameandpartners/website that referenced this issue Mar 7, 2017
* 404 page redesign

* Fix css format

* Fix link destination

* Remove old 404 file

* Add new controller and helper

* Add new 404 template

* Add new route to the 404 page

* Tell rails to use tempaltes

* Error pages sass

* Catch errors with custom error pages yielded w/ application layout

* update styling and put content inside .container

* Optimize calls + raise exception for development mode

* Return back static 500 page

* Make rails app available to catch RoutingError (raised by ActionDispatch)

Ref: rails/rails#671

* Fix not found routes spec

* Fix unmactched routes catch

* Fix specs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests