为什么在这个Rails方法中无法获救ActiveRecord :: StatementInvalid?

Cla*_*ani 2 activerecord ruby-on-rails exception rescue

为什么我不能用以下方法拯救任何东西?

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
Run Code Online (Sandbox Code Playgroud)

使用有效ID调用时,它可以工作:

$  curl -vd "id=3" http://localhost:3000/get_things
Run Code Online (Sandbox Code Playgroud)

但如果我错了一个,例如:

$  curl -vd "id=3,0" http://localhost:3000/get_things
$  curl -vd "id='3'" http://localhost:3000/get_things
Run Code Online (Sandbox Code Playgroud)

异常未获救:

< 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;
Run Code Online (Sandbox Code Playgroud)

仅在渲染发生在开始/救援块内时

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
Run Code Online (Sandbox Code Playgroud)

它按预期工作:

$ curl -vd "id='3'" http://localhost:3000/get_things
  < HTTP/1.1 200 OK
  RESCUED ActiveRecord::StatementInvalid
Run Code Online (Sandbox Code Playgroud)

Mat*_*tzi 7

据我所知,things在您的情况下,将是一个包含查询信息的类,但在您尝试根据查询(例如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
Run Code Online (Sandbox Code Playgroud)

这就是它无法获救的原因,因为在渲染线中,发生异常的地方,而不是在创建中things.

这应该没问题:

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
Run Code Online (Sandbox Code Playgroud)