我正在使用Ruby on Rails开发REST Web服务。
在每个请求之后,我想在数据库中存储响应HTTP状态代码,即使存在一些异常。我怎么能这样做?
我做了这两次尝试都没有成功:
应用程序控制器中的after_filter
class Api::ApiController < ActionController::Base
before_action :set_current_rest_request
after_filter :finalize_current_rest_request
private
def set_current_rest_request
@current_rest_request = RestRequest.new
@current_rest_request.request_at = DateTime.now
@current_rest_request.save
end
def finalize_current_rest_request
@current_rest_request.answer_at = DateTime.now
@current_rest_request.http_status_code = response.status
@current_rest_request.save
end
end
不起作用,因为在异常的情况下不会调用finalize_current_rest_request
应用程序控制器中的rescue_from
class Api::ApiController < ActionController::Base
before_action :set_current_rest_request
after_filter :finalize_current_rest_request
rescue_from Exception, :with => :handle_exception
private
def set_current_rest_request
@current_rest_request = RestRequest.new
@current_rest_request.request_at = DateTime.now
@current_rest_request.save
end
def finalize_current_rest_request
@current_rest_request.answer_at = DateTime.now
@current_rest_request.http_status_code = response.status
@current_rest_request.save
end
def handle_exception(exception)
finalize_current_rest_request
raise exception
end
end
因为在异常引发之前我在handle_exception中调用finalize_current_rest_request
答案 0 :(得分:0)
您需要使用开始救援块来包装控制器的每个操作。类似的东西:
begin
respond_to do |format|
format.json { redirect_to foos_path, notice: 'Foo was successfully destroyed.' }
rescue
@current_rest_request.http_status_code = response.status
end
end
通常这样的行为留给了日志,但我假设你有充分的理由这样做。
如果你真的希望它如你所提到的那样干,你可以放入你的应用程序控制器:
rescue_from Exception, :with => :store_request
def store_request
current_rest_request = RestRequest.new
current_rest_request.request_at = DateTime.now
current_rest_request.http_status_code = response.status
current_rest_request.save
end
注意:在应用程序控制器中进行全面救援通常被认为是不好的做法。我认为实际处理此问题的最佳方法是实施全面的日志记录方案。
答案 1 :(得分:0)
我终于解决了添加中间件的问题(here一些有关Rails中间件如何工作的数据)。 详细地,在config / application.rb中,我添加了:
config.middleware.insert_before "Rails::Rack::Logger","StoreStatus"
api控制器是
class Api::ApiController < ActionController::Base
before_action :set_current_rest_request
private
def set_current_rest_request
@current_rest_request = RestRequest.new
request.env[:current_rest_request] = @current_rest_request
end
end
我添加了带有以下代码的文件lib / store_status.rb:
class StoreStatus
def initialize(app)
@app = app
end
def call(env)
data = @app.call(env)
if (env[:current_rest_request])
rest_request = env[:current_rest_request]
rest_request.http_status_code = data[0]
rest_request.save
end
data
end
end
请注意,可能会出现一些语法错误,因为已获得该代码,从而重构了包含此问题其他无用的复杂性的代码。