Rails: Custom behavior for specific HTTP error codes - ruby-on-rails

I am working on a RoR website and would like to handle server errors (400, 404, 500, etc.) individually. Also, since the website is dynamic I would like to handle the errors within the rails environment rather than at the server level.
An example of what I would like to do could be to present the user with optional material or a search bar when she bumps into a page or template that will not load or simply does not exist.
So, I did a bit of reading and I think that using the rescue_from exception handler is the way to go in my case. (Would be more than happy to hear if any of you have a different opinion).
I have a simple working prototype (see code below) up and running, however, I get an error when I include the following exception handler to the code:
rescue_from ActionController::MissingTemplate, :with => :not_found #404
Now, I can't see that I have a spelling error and I have seen this line in code posted on the web. However, when I include it I get the following routing error:
Routing Error No route matches "/errorhandle" with {:method=>:get}
I am working on rails 2.3.5, perhaps that has got something to do with it?
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
protect_from_forgery #See ActionController::RequestForgeryProtection for details
#ActiveRecord exceptions
rescue_from ActiveRecord::RecordNotFound, :with => :not_found #400
#ActiveResource exceptions
rescue_from ActiveResource::ResourceNotFound, :with => :not_found #404
#ActionView exceptions
rescue_from ActionView::TemplateError, :with => :not_found #500
#ActionController exceptions
rescue_from ActionController::RoutingError, :with => :not_found #404
rescue_from ActionController::UnknownController, :with => :not_found #404
rescue_from ActionController::MethodNotAllowed, :with => :not_found #405
rescue_from ActionController::InvalidAuthenticityToken, :with => :not_found #405
rescue_from ActionController::UnknownAction, :with => :not_found #501
# This particular exception causes all the rest to fail.... why?
# rescue_from ActionController::MissingTemplate, :with => :not_found #404
protected
def not_found
render :text => "Error", :status => 404
end
# Scrub sensitive parameters from your log
# filter_parameter_logging :password
end

Take a quick look at these:
http://www.ruby-forum.com/topic/47898
http://henrik.nyh.se/2008/09/404-invalid-rails-format
In particular, a post in the first link:
You can't use a regular 'rescue' keyword to rescue MissingTemplate
exception.
Use rescue_action instead, for example:
def rescue_action(exception)
if ::ActionController::MissingTemplate === exception
render :text => 'rescued'
else
super
end
end
Kent.

Related

How to rescue_from ActionDispatch::Cookie::CookieOverflow?

First at all, I have read:
Cookie overflow in rails application?
And this is not the problem that I'm facing.
I'm working with:
gem "rails", "~> 3.2.11"
and
ruby 1.9.3-p125
I'm trying to process a search, and when the search is tooooooo big I get this error:
ActionDispatch::Cookies::CookieOverflow
I would like to rescue_form this error in the ApplicationController but it seems that is not working for me:
rescue_from ActionDispatch::Cookies::CookieOverflow :with => :render_404
where:
def render_404
respond_to do |r|
r.html { render :template => "something/404", :status => 404}
r.all { render :nothing => true, :status => 404 }
end
true
end
any help is going to be well received.
rescue_from ActionDispatch::Cookies::CookieOverflow :with => :render_404
you are missing comma (,) in arguments , according to docs
with correc syntax
rescue_from ActionDispatch::Cookies::CookieOverflow, with: :render_404
rescue_from receives a series of exception classes or class names, and
a trailing :with option with the name of a method
see more:
http://api.rubyonrails.org/v5.0/classes/ActiveSupport/Rescuable/ClassMethods.html

How to properly render custom 404 and 500 pages?

Is there are way to tell Rails to render your custom error pages (for example, the ones you write in your ErrorsController)? I've searched many topics, and the one that seems to kinda work was to add to your ApplicationController something like
if Rails.env.production?
rescue_from Exception, :with => :render_error
rescue_from ActiveRecord::RecordNotFound, :with => :render_not_found
rescue_from ActionController::UnknownController, :with => :render_not_found
rescue_from ActionController::UnknownAction, :with => :render_not_found
end
and then you write your methods render_error and render_not_found the way you want. This seems to me like a really unelegant solution. Also, it's bad, because you have to know exactly what are all the errors that could happen. It's a temporary solution.
Also, there is really no easy way to rescue an ActionController::RoutingError that way. I saw that one way was to add something like
get "*not_found", :to => "errors#not_found"
to your routes.rb. But what if you want to raise somewhere an ActionController::RoutingError manually? For example, if a person who is not an administrator tries to go to "adminy" controllers by guessing the URL. In those situations I prefer raising a 404 more than raising an "unauthorized access" error of some kind, because that would actually tell the person that he guessed the URL. If you raise it manually, it will try to render a 500 page, and I want a 404.
So is there a way to tell Rails: "In all cases you would normally render a 404.html or a 500.html, render my custom 404 and 500 pages"? (Of course, I deleted the 404.html and 500.html pages from the public folder.)
Unfortunately there aren't any methods I know of that can be overridden to provide what you want. You could use an around filter. Your code would look something like this:
class ApplicationController < ActionController::Base
around_filter :catch_exceptions
protected
def catch_exceptions
yield
rescue => exception
if exception.is_a?(ActiveRecord::RecordNotFound)
render_page_not_found
else
render_error
end
end
end
You can handle each error as you see fit in that method. Then your #render_page_not_found and #render_error methods would have to be something like
render :template => 'errors/404'
You would then need to have a file at app/views/errors/404.html.[haml|erb]

rails handle 404 with url redirect

I am looking to use rails to redirect links that I am sure are out there on the internet from an old domain of mine to a new one.
I would like to take address example.com/about ( about will not exist anymore)
and in my application_controller to take the 404, inspect the url and then redirect to
newexample.com/about
what's the best way to do this?
Add this to the end of your Routes file:
map.connect '*path', :controller => 'some_controller', :action => 'some_action'
This will catch any 404. Within the controller and action that will handle this route, use params[:path] to examine the url. Then you can redirect_to based on whatever is contained in params[:path].
You need to use rescue_from. In your ApplicationController, add something like:
rescue_from ActionController::RoutingError, :with => :redirect_missing
rescue_from ActionController::UnknownController, :with => :redirect_missing
rescue_from ActionController::UnknownAction, :with => :redirect_missing
def redirect_missing
redirect_to "http://newexample.com/about"
end

What all exceptions map to 404.html and what exceptions map to 500.html

I am using rails3 and am looking for the list of all exceptions that would show 404.html and the list of exceptions that would map to 500.html in PRODUCTION mode.
Right now I need to add something like
rescue_from ActiveRecord::RecordNotFound, :with => :render_404
in my application_controller and I don't like it. I think Rails should handle it automatically.
I'm doing this in my application controller:
rescue_from Exception, :with => :handle_error
def handle_error(exception)
if exceptions_to_treat_as_404.include?(exception.class)
render_404
else
raise exception if Rails.env == 'development'
body = exception_error_message(exception)
#to logger
logger.fatal( body )
#to email
from = '<errors#peakdemocracy.com>'
recipients = "<robert#peakdemocracy.com>"
subject = "[ERROR] (#{exception.class}) #{exception.message.inspect}"
GenericEmail.create(:subject => subject, :from => from, :recipients => recipients, :body => body)
#to PageRequest table
log_request(true)
#render error message
render_500
end
end
def exceptions_to_treat_as_404
exceptions = [AbstractController::ActionNotFound,
ActiveRecord::RecordNotFound,
ActionController::UnknownController,
URI::InvalidURIError,
ActionController::UnknownAction]
exceptions << ActionController::RoutingError if ActionController.const_defined?(:RoutingError)
exceptions
end
Rails will show the 404 error whenever it can't properly map the requested URL to a controller/action (i.e. the path doesn't match any of your routes). Any other unhandled exception will show the 500 error instead.

Custom Error Page - Ruby on Rails

I am trying to setup a custom error page in my website. I am following the guidelines atPerfectLine Blog.
It works in the case where the controller exists, but the id does not exist. For example, I have a blog controller and id 4 does not exist. It shows the custom error page
But it does not exist in the case, where controller itself does not exist. For example, if I type some random controller with a numeric id does not gets caught by the methods I have setup in the application controller to re-route the custom error pages. In this case, I get an
ActionController::RoutingError (No route matches "/randomcontrollername"):
in the terminal and the default error page that comes with rails.
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, :with => :render_error
rescue_from ActiveRecord::RecordNotFound, :with => :render_not_found
rescue_from ActionController::RoutingError, :with => :render_not_found
rescue_from ActionController::UnknownController, :with => :render_not_found
rescue_from ActionController::UnknownAction, :with => :render_not_found
end
private
def render_not_found(exception)
render :template => "/error/404.html.erb", :status => 404
end
def render_error(exception)
render :template => "/error/500.html.erb", :status => 500
end
end
Could you please help me. Thanks.
You can do that with route globbing in rails, It lets you match any action to any part of a route using wildcards.
To catch all remaining routes, just define a low priority route mapping as the last route in config/routes.rb:
In Rails 3:
match "*path" => 'error#handle404'
In Rails 2:
map.connect "*path", :controller => 'error', :action => 'handle404'
params[:path] will contain the matching part.
If you don't need dynamic error pages, just edit public/404.html and public/505.html. If you do, see Reza.mp's answer.

Resources