How to return correct HTTP error codes from Ruby o

2019-03-14 08:21发布

问题:

I have RoR 3.0 web application which is acting as an OAuth API provider. Now, in API I'd like to return correct HTTP error codes to the API consumer. How do I do this?

Here is example:

def destroy_oauth
    @item = Item.find(params[:id])
    if(!@item.nil? && @item.user_id == current_user.id)
        @item.destroy
        respond_to do |format|
                format.js
                format.xml
        end
    else
        raise ActionController::RoutingError.new('Forbidden')
    end
end

So, in case of error I'm trying to return Forbidden 403 code. Still, when running this I'm getting always 404 Not Found returned. How do I return the correct code?

Or is this somehow webserver configurable thing?

回答1:

You should render page with correct status.

render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false)


回答2:

When you're just giving a status code and there is no body, a convenient way is

head 403

This method also accepts the symbolic names for status codes, such as

head :forbidden


回答3:

According to ActionController::Head docs just use this pattern in actions

  return head([status]) if/unless [some condition here]

Example:

  return head(:gone) if @record.deleted?
  return head(:forbidden) unless @user.owns?(@record)

return is used to make sure that no remaining code in the action will be run.



回答4:

well, you can use

:status =>500

But, In default Rails take care of the error type rendering itself.

Errors default pages are in the public directory. 500.html,404.html etc..

For more information on :status , how to use it click here



回答5:

I think you have two problems here: first is that your @item = Item.find(params[:id]) line is raising 404 and execution never gets to where intended (if statement). Second is that you are raising exceptions and never catch them. Try:

def destroy_oauth
   begin
     @item = Item.find(params[:id])
     if(!@item.nil? && @item.user_id == current_user.id)
       @item.destroy
       respond_to do |format|
          format.js
          format.xml
       end
     else
       raise ActionController::RoutingError.new('Forbidden')
     end
   rescue ActiveRecord::ResourceNotFound
     redirect_to :action => 'not_found', :status => 404 # do whatever you want here
   rescue ActionController::RoutingError
     redirect_to :action => 'forbidden', :status => 403 # do whatever you want here
   end
 end

Something along those lines, but you also mentioned that you are building the API, so when you are rescuing the error, you may want to render xml error info. Something like:

# in application_controller.rb
rescue_from ActionController::RoutingError, :with => :render_forbidden_error

private

def render_forbidden_error(e)
  render :status => e.status, :xml => e
end

Good luck. Udachi.