Rails用jbuilder显示错误的正确方法

时间:2013-04-04 20:06:13

标签: ruby-on-rails ruby json jbuilder

我希望在jbuilder视图中显示错误消息。例如,我可能有一条路线:

/foos/:id/bars

如果用户提交的:id不存在或无效,我希望能够在index.json.builder文件中相应地显示错误消息。

使用Rails,完成这项工作的最佳方法是什么?控制器可能包含以下内容:

def index
  @bar = Bar.where(:foo_id => params[:id])
end

在这种情况下,params[:id]可能是nil,或者该对象可能不存在。我不确定这里做的最好的事情是在控制器中处理它并显式呈现error.json.builder,或者在index.json.builder视图本身处理它。这样做的正确方法是什么?如果它在index.json.builder中,params[:id]可以在那里查看吗?我知道我可以看到@bar.nil?但是反过来不确定吗?

2 个答案:

答案 0 :(得分:4)

我会使用:error => 'not found'呈现index.json.builder或内联json 并且不要忘记设置正确的HTTP状态::status => 404

所以结果看起来像这样:

render :json => { :error => 'not found' }, :status => 422 if @bar.nil?

答案 1 :(得分:4)

我认为你的意思是show,因为索引实际上是列表/集合。你应该得到.first,否则你只是有关系,对吗?然后,使用.first!引发错误,因为Rails 4 public_exceptions中的Rails'Rack中间件将以基本方式处理,例如。

def show
  # need to do to_s on params value if affected by security issue CVE-2013-1854
  @bar = Bar.where(:foo_id => params[:id].to_s).first!
end

您也可以使用@bar = Bar.find(params[:id]),但这已弃用,将在Rails 4.1中删除,之后您必须将gem 'activerecord-deprecated_finders'添加到您要使用的Gemfile中。

对于索引,您可能需要@bars = Bar.all。如果由于某种原因你想要过滤并且不想要范围等,那么你可以使用@bars = Bar.where(...).to_a或类似的。

Rails 4:机架中的基本异常处理是自动的

只要查询启动错误,Rails 4应该能够返回错误的消息部分,因为任何支持的格式where to_(format)都可以在哈希上调用(例如json,xml等)

要了解原因,请查看Rails的Rack public_exceptions中间件。

如果是html,它将尝试从Rails中的公共目录中读取相关文件中的状态代码(例如,500.html表示服务器错误/ HTTP 500)。

如果是其他格式,它会尝试对哈希值to_(the format) { :status => status, :error => exception.message }$ rails c ... 1.9.3p392 :001 > {status: 500, error: "herro shraggy!"}.to_xml => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <status type=\"integer\">500</status>\n <error>herro shraggy!</error>\n</hash>\n" 1.9.3p392 :002 > {status: 500, error: "herro shraggy!"}.to_json => "{\"status\":500,\"error\":\"herro shraggy!\"}" 。要了解这将如何工作,请转到Rails的控制台:

X-Cascade

在中间件中,您将看到代码中的X-Cascade标头以及与Rails在Rack中的异常处理相关的各种位置。根据{{​​3}},pass标头设置为to_(format),以告知Rack尝试其他路由来查找资源。

Rails 3.2.x:可以处理Rack

中的异常

在Rails 3.2.x中,为config.exceptions_app = self.routes提供的响应正文config.consider_all_requests_local = false代码不在this answer中。它只处理html格式。

也许您可以尝试通过补丁更新旧版本的中间件。

如果您希望Rack在没有补丁的情况下以更具体的方式处理您的错误,请参阅JoséValim的帖子中的#3,“public_exceptions.rb”。

在此中,My five favorite “hidden” features in Rails 3.2也提及,您可以使用config/environments/development.rb。然后使用指向自定义控制器的路由,您可以像任何其他请求一样处理来自任何控制器的错误。请注意exceptions_app中的[http_status_code_number, {headers hash...}, ['the response body']]位。

您不必使用路由来使用config.exceptions_app = lambda do |env| exception = env["action_dispatch.exception"] status = env["PATH_INFO"][1..-1] request = ActionDispatch::Request.new(env) content_type = request.formats.first body = { :status => status, :error => exception.message } format = content_type && "to_#{content_type.to_sym}" if format && body.respond_to?(format) formatted_body = body.public_send(format) [status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [formatted_body]] else found = false path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path)) if found || File.exist?(path) [status, {'Content-Type' => "text/html; charset=#{ActionDispatch::Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [File.read(path)]] else [404, { "X-Cascade" => "pass" }, []] end end end 。虽然它可能有点令人生畏,但它只是一个proc / lambda,它接受一个哈希并返回一个格式为ActionDispatch::ShowExceptions的数组。例如,您应该能够在Rails 3.2.x配置中执行此操作,以使其处理Rails 4.0之类的错误(这是最新的public_exceptions中间件崩溃):

def show
  respond_with @bar = Bar.where(:foo_id => params[:id].to_s).first!
rescue ActiveRecord::RecordNotFound => e
  respond_to do |format|
    format.json => { :error => e.message }, :status => 404
  end
end

注意:对于该处理的任何问题,故障安全实施位于def show @bar = Bar.where(:foo_id => params[:id].to_s).first if @bar respond_with @bar else respond_to do |format| format.json => { :error => "Couldn't find Bar with id=#{params[:id]}" }, :status => 404 end end end another answer

Rails 3和4:处理Rails控制器中的一些异常

如果你想在控制器本身中进行错误渲染,你可以这样做:

rescue_from ActiveRecord::RecordNotFound, with: :not_found

def not_found(exception)
  respond_to do |format|
    format.json => { :error => e.message }, :status => 404
  end
end

但是,您不需要提出错误。你也可以这样做:

rescue_from ActiveRecord::RecordNotFound do |exception|
  respond_to do |format|
    format.json => { :error => e.message }, :status => 404
  end
end

您也可以使用here,例如在您的控制器或ApplicationController等中:

{{1}}

或:

{{1}}

虽然可以在控制器中处理一些常见错误,但如果您在json等格式化错误路由等错误,则需要在Rack中间件中处理。