I'm developing a REST web service in Ruby on Rails.
After each request I would like to store in the database the response HTTP status code even in presence of some exception. How can I do that?
I have done these two attempts without success:
after_filter in application controller
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
Doesn't work because finalize_current_rest_request is not called in case of exceptions
rescue_from in application controller
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
Doesn't work because response.status is still 200 when I call finalize_current_rest_request inside handle_exception, before the raise of the exception
You need to wrap each action of the controller with a begin rescue block. Something like:
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
Normally behavior like this is left up to the logs but I am assuming you have a really good reason for doing this.
If you really want it to be dry as you mentioned you can put in your application controller:
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
Note: It is often considered bad practice to blanket rescue in the application controller. I think the best way to actually handle this is to implement a comprehensive logging scheme.
I finally solved adding a middleware ( here some datails on how rails middlewares work). In detail, in config/application.rb, I added:
config.middleware.insert_before "Rails::Rack::Logger","StoreStatus"
the api controller was
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
and I added the file lib/store_status.rb with the following code:
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
Please notice that there may be some syntax error because this code has been obtained refactoring a code which contains other useless complexity for this question.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.