Rails applications are known of producing 500 Server Failure responses en masse. Most of them are coused by two actions:
- using find(id)
- referencing nil
In most cases both can be safetly avoided and turned into more user friendly 400 responses.
What is wrong with find(id)
ActiveRecord find(id) method is a single point of failure of most programs.
Find(id) throws exception when it can not find record with given id. That's right. No nil return, just exception which is propagated out of the action and results in 500 error.
A lot better solution is to use dynamic find_by_id(id) method which returns nil when called.
Is 400 a good response?
That depends on the context. But in most cases the answer is yes.
Actions expect to receive valid ids. When action receives invalid id it is usually caused by:
- invalid link in the application
- invalid link outside of application
- user toyed with request url
In all of those cases sending 400 status and proper 'Missing page' page is the best what we can do.
And how about redirect instead of 400?
Redirect breaks things. First, search engines rely on 400 to remove missing links. If they receive redirect, they follow it and record broken link in their database as valid, redirected.
Second, it is hard for user to tell support what exactly happened as url changes and can not be provided to troubleshoot.
Third, user ends up on page he wasn't expecting which *is not* an error page, thus creating confusion.
How to properly handle such situations?
se following schema when dealing with user-provided ids:
def show_message
message = Message.find_by_id(params[:id])
send_missing("Could not find message") and return unless message
# Message is present, lets do something with it
# ...
end
Where send_missing is something among the lines of:
# Sets response code to 404 and renders 'missing resource' template
def send_missing(message = "Missing resource, sending 404")
logger.debug message
render(:template => 'common/404', :status => 404)
end
How to guard against nil referencing
Validate data before using it (in controller, data provided to view should always be valid). Ensure proper relationships and valid data using ActiveRecord validations.
1 comments:
Or you could just do this...
class ApplicationController
def rescue_action_in_public(exception)
case exception
when ::ActiveRecord::RecordNotFound
render :text => "Page Not Found", :status => 404
end
end
end
Post a Comment