Search code examples
ruby-on-railsexceptionactiverecordrescue

Why ActiveRecord::StatementInvalid cannot be rescued in this Rails method?


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: &quot;'3'&quot;

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