Reputation: 558
In my controller controller, I have use Date.new
to create a date object to be passed in my ActiveRecord.
end_range = Date.new(params[:year].to_i, params[:month].to_i, params[:day].to_i).end_of_day.to_formatted_s(:db)
The problem with this above is that if a user tried to change the parameters in the URL manually, such as entering 40
for the day param, the Date.new
fails (as expected). However, I would rather not have a 500 error if a user typed in something like that, but instead a 404 error (because you will never actually be able a record with a day of 40
).
I tried various conditionals (if
and unless
statements) to raise ActiveRecord::RecordNotFound
if that fails, but it returns the 500 error before running the conditional (and therefor never returning a 404).
Does anybody know a better way to handle that, or a way to allow the Date.new
to fail more gracefully so that the conditional statement can run?
Upvotes: 12
Views: 46407
Reputation: 2470
I think it makes more sense to rescue an invalid date error with a useful message. This is a common problem when people select 30 February for example. I would rather send them back to the form in question and tell them why they are getting sent back. A 404 would be wrong in most cases, since the error is invalid user input, not an invalid URL.
Further, if you rescue all ArgumentError
s then you won't get notified of other code-related bugs. So if it's not a date error then I'm re-raising the error. Unfortunately we have to change the exception type to avoid a loop.
I've put this in the application_controller:
rescue_from ArgumentError do |exception|
if exception.message == 'invalid date'
flash[:error] = exception.message
redirect_to request.referer ? :back : root_url
else
raise StandardError, exception.message, exception.backtrace
end
end
Upvotes: 1
Reputation: 211560
In this case you might rescue one exception and raise another if you'd like to re-map exceptions that aren't handled into the kind that are:
def show
begin
end_range = Date.new(...)
rescue ArgumentError
# Invalid date
raise ActiveRecord::RecordNotFound
end
rescue ActiveRecord::RecordNotFound
render(:partial => 'not_found', :layout => 'application', :status => :not_found)
end
It might be more efficient to simply render and fail right away though.
def show
begin
end_range = Date.new(...)
rescue ArgumentError
return render(:partial => 'date_not_found', :layout => 'application', :status => :not_found)
end
end
You can also do this in a more sweeping sense using the rescue_from
method of ApplicationController:
class ApplicationController < ActionController::Base
rescue_from 'ArgumentError do
render(:partial => 'exceptions/argument_error', :layout => 'application', :status => :not_found)
end
end
Upvotes: 34