首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Ruby/Sinatra中,如何使用ERB模板和错误消息停止

在Ruby/Sinatra中,如何使用ERB模板和错误消息停止
EN

Stack Overflow用户
提问于 2016-03-21 09:20:31
回答 2查看 3.4K关注 0票数 6

在我的Sinatra项目中,我希望能够使用错误代码和错误消息来停止:

代码语言:javascript
复制
halt 403, "Message!"

我希望这反过来被呈现在一个错误页面模板中(使用ERB)。例如:

代码语言:javascript
复制
error 403 do
    erb :"errors/error", :locals => {:message => env['sinatra.error'].message}
end

然而,显然env['sinatra.error'].message (又名自述和每个网站都说我应该这么做)并没有公开我提供的信息。(运行此代码时,将返回undefined method `message' for nil:NilClass错误。)

我已经搜索了4-5个小时,并尝试了所有的东西,我不知道信息在哪里暴露给我通过再培训局渲染!有人知道它在哪吗?

(这似乎是我所能想到的唯一选择,就是编写这段代码,而不是上面的halt代码,每次我想停下来:

代码语言:javascript
复制
halt 403, erb(:"errors/error", :locals => {m: "Message!"})

这个密码起作用了。但是这是一个混乱的解决方案,因为它涉及硬编码错误ERB文件的位置。)

(如果您想知道,这个问题与show_exceptions配置标志无关,因为set :show_exceptions, falseset :show_exceptions, :after_handler都没有区别。)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-22 09:15:04

为什么它不能工作,−使用源代码!

让我们看一下Sinatra的源代码,看看为什么这个问题不起作用。主要的Sinatra文件(lib/sinatra/base.rb)只有2043行长,而且代码可读性很强!

halt所做的就是:

代码语言:javascript
复制
def halt(*response)
  response = response.first if response.length == 1
  throw :halt, response
end

例外情况有:

代码语言:javascript
复制
# Dispatch a request with error handling.
def dispatch!
  invoke do
    static! if settings.static? && (request.get? || request.head?)
    filter! :before
    route!
  end
rescue ::Exception => boom
  invoke { handle_exception!(boom) }
  [..]
end

def handle_exception!(boom)
  @env['sinatra.error'] = boom
  [..]
end

但出于某种原因,这段代码从未运行过(使用基本的“printf-调试”进行了测试)。这是因为在invoke中,块的运行方式如下:

代码语言:javascript
复制
# Run the block with 'throw :halt' support and apply result to the response.
def invoke
  res = catch(:halt) { yield } 
  res = [res] if Fixnum === res or String === res
  if Array === res and Fixnum === res.first
    res = res.dup
    status(res.shift)
    body(res.pop)
    headers(*res)
  elsif res.respond_to? :each
    body res
  end
  nil # avoid double setting the same response tuple twice
end

注意这里的catch(:halt)if Array === res and Fixnum === res.first部分是halt设置的内容以及响应主体和状态代码的设置方式。

error 403 { .. }块在call!中运行

代码语言:javascript
复制
invoke { error_block!(response.status) } unless @env['sinatra.error']

现在我们明白了为什么这行不通,我们可以找出解决办法;-)

我能用点什么方法吗?

据我所知没有。如果您查看invoke方法的主体,您将看到在使用halt时总是设置主体。您不想这样做,因为您想要覆盖响应体。

解决方案

使用“真实”异常,而不是halt“伪异常”。Sinatra似乎没有预定义的异常,但是handle_exception!确实会查看http_status来设置正确的HTTP状态:

代码语言:javascript
复制
  if boom.respond_to? :http_status
    status(boom.http_status)
  elsif settings.use_code? and boom.respond_to? :code and boom.code.between? 400, 599
    status(boom.code)
  else
    status(500)
  end

所以你可以用这样的东西:

代码语言:javascript
复制
require 'sinatra'

class PermissionDenied < StandardError
    def http_status; 403 end
end

get '/error' do
    #halt 403, 'My special message to you!'
    raise PermissionDenied, 'My special message to you!'
end

error 403 do
    'Error message -> ' +  @env['sinatra.error'].message
end

如预期的那样工作(输出为Error message -> My special message to you!)。您可以在这里返回一个ERB模板。

票数 7
EN

Stack Overflow用户

发布于 2019-12-11 11:17:58

在Sinatra v2.0.7+中,传递给halt的消息存储在响应体中。因此,可以捕获带有错误代码和错误消息(例如:halt 403, "Message!")的错误页模板,并将其呈现为:

代码语言:javascript
复制
error 403 do
  erb :"errors/error", locals: { message: body[0] }
end
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36127041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档