gpt4 book ai didi

ruby-on-rails - 如何从 Rails 4 中的 ActionDispatch::ParamsParser::ParseError 中解救出来

转载 作者:数据小太阳 更新时间:2023-10-29 06:41:49 24 4
gpt4 key购买 nike

Rails 4 添加了一个异常 ActionDispatch::ParamsParser::ParseError 异常,但由于它在中间件堆栈中,所以它似乎无法在正常的 Controller 环境中被挽救。在 json API 应用程序中,我希望使用标准错误格式进行响应。

gist显示了插入中间件以进行拦截和响应的策略。按照这种模式,我有:

application.rb:

module Traphos
class Application < Rails::Application
....
config.middleware.insert_before ActionDispatch::ParamsParser, "JSONParseError"
end
end

中间件是:

class JSONParseError
def initialize(app)
@app = app
end

def call(env)
begin
@app.call(env)
rescue ActionDispatch::ParamsParser::ParseError => e
[422, {}, ['Parse Error']]
end
end
end

如果我在没有中间件的情况下运行测试,我会得到(规范):

Failures:

1) Photo update attributes with non-parseable json
Failure/Error: patch update_url, {:description => description}, "CONTENT_TYPE" => content_type, "HTTP_ACCEPT" => accepts, "HTTP_AUTHORIZATION" => @auth
ActionDispatch::ParamsParser::ParseError:
399: unexpected token at 'description=Test+New+Description]'

这正是我所期望的(我无法 rescue_from 的 ParseError)。

现在在上面的中间件中添加唯一的更改:

  2) Photo update attributes with non-parseable json
Failure/Error: response.status.should eql(422)

expected: 422
got: 200

并且日志显示正在执行标准 Controller 操作并返回正常响应(尽管因为它没有收到任何参数,所以没有更新任何内容)。

我的问题:

  1. 如何从 ParseError 中解救并返回自定义响应。感觉我走在正确的 rails 上,但又不完全正确。

  2. 我不明白为什么在引发并挽救异常时, Controller 操作仍在继续。

非常感谢,--Kip

最佳答案

事实证明,在中间件堆栈的更上层,ActionDispatch::ShowExceptions 可以配置一个异常应用。

module Traphos
class Application < Rails::Application
# For the exceptions app
require "#{config.root}/lib/exceptions/public_exceptions"
config.exceptions_app = Traphos::PublicExceptions.new(Rails.public_path)
end
end

主要基于我现在使用的 Rails:

module Traphos
class PublicExceptions
attr_accessor :public_path

def initialize(public_path)
@public_path = public_path
end

def call(env)
exception = env["action_dispatch.exception"]
status = code_from_exception(env["PATH_INFO"][1..-1], exception)
request = ActionDispatch::Request.new(env)
content_type = request.formats.first
body = {:status => { :code => status, :exception => exception.class.name, :message => exception.message }}
render(status, content_type, body)
end

private

def render(status, content_type, body)
format = content_type && "to_#{content_type.to_sym}"
if format && body.respond_to?(format)
render_format(status, content_type, body.public_send(format))
else
render_html(status)
end
end

def render_format(status, content_type, body)
[status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}",
'Content-Length' => body.bytesize.to_s}, [body]]
end

def render_html(status)
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)
render_format(status, 'text/html', File.read(path))
else
[404, { "X-Cascade" => "pass" }, []]
end
end

def code_from_exception(status, exception)
case exception
when ActionDispatch::ParamsParser::ParseError
"422"
else
status
end
end
end
end

要在测试环境中使用它需要设置配置变量(否则您将在开发和测试中获得标准的异常处理)。所以为了测试我有(编辑只有关键部分):

describe Photo, :type => :api do
context 'update' do
it 'attributes with non-parseable json' do

Rails.application.config.consider_all_requests_local = false
Rails.application.config.action_dispatch.show_exceptions = true

patch update_url, {:description => description}
response.status.should eql(422)
result = JSON.parse(response.body)
result['status']['exception'].should match(/ParseError/)

Rails.application.config.consider_all_requests_local = true
Rails.application.config.action_dispatch.show_exceptions = false
end
end
end

它以公共(public) API 方式按我的需要执行,并且适用于我可能选择自定义的任何其他异常。

关于ruby-on-rails - 如何从 Rails 4 中的 ActionDispatch::ParamsParser::ParseError 中解救出来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15459143/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com