Why ActiveRecord::StatementInvalid cannot be rescued in this Rails method?
-
20-06-2021 - |
Question
Why I cannot rescue anything in the following method?
def get_things
begin
things= @member.things.where("id>?",params[:id])
rescue ActiveRecord::StatementInvalid
render( inline: "RESCUED ActiveRecord::StatementInvalid" )
return
rescue
render( inline: "RESCUED something" )
return
end
render( inline: "#{things.first.title}" )
end
When called with a valid id, it works:
$ curl -vd "id=3" http://localhost:3000/get_things
but if I pass a wrong one, such as:
$ curl -vd "id=3,0" http://localhost:3000/get_things
$ curl -vd "id='3'" http://localhost:3000/get_things
the exception isn't rescued:
< HTTP/1.1 500 Internal Server Error
<h1>
ActiveRecord::StatementInvalid
in ApplicationController#get_things
</h1>
<pre>PG::Error: ERROR: invalid input syntax for integer: "'3'"
Only when rendering happens inside begin/rescue block
def get_things
begin
things= @member.things.where("id>?",params[:id])
render( inline: "#{things.first.title}" )
rescue ActiveRecord::StatementInvalid
render( inline: "RESCUED ActiveRecord::StatementInvalid" )
return
end
end
it works as expected:
$ curl -vd "id='3'" http://localhost:3000/get_things
< HTTP/1.1 200 OK
RESCUED ActiveRecord::StatementInvalid
Solution
As far as I know, the things
in your case will be a class containg information on your query, but the query won't be executed till you try to acces an element based on the query (like things.first
).
things= @member.things.where("id>?",params[:id]) # query not run
things= things.order("id desc") # still not run
things.first.title # now the query runs, the statement can be invalid
This is why it can't be rescued, because in your render line, where the exception occurs, not in the creation of the things
.
This should be okay:
def get_things
begin
things= @member.things.where("id>?",params[:id])
thing_title = things.first.title
rescue ActiveRecord::StatementInvalid
render( inline: "RESCUED ActiveRecord::StatementInvalid" )
return
rescue
render( inline: "RESCUED something" )
return
end
render( inline: "#{thing_title}" )
end
OTHER TIPS
You can change a parameter to int:
params[:id] = params[:id].to_i if params[:id].present?
things= @member.things.where("id>?",params[:id])
Or you can add validator for params in config/routes.rb
:
resources :things, :constraints => {:id => /\d+/}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow