44

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([email protected]? && @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?

5 Answers 5

69

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
Sign up to request clarification or add additional context in comments.

1 Comment

Oh, that could be what I need. Will try.
50

You should render page with correct status.

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

3 Comments

Should I do this also for OAuth API xml responses?
As a side-note here, specifying the .html extension like this is deprecated (see discussion at github.com/rails/rails/issues/7288), so we should use render(:file => File.join(Rails.root, 'public/403'), :formats => [:html], :status => 403, :layout => false) (note the way I've specified the format).
... or even render(:file => Rails.root.join('public', '403'), :formats => [:html], :status => 403, :layout => false).
19

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.

2 Comments

Is there any difference between head :forbidden && return and return head :forbidden? In my testing,I had to use the latter to return early from controller. With the former, I got 204 returned.
@wlnirvana Ahhhh that's why I was getting a 204 No Content returned, I couldn't understand why head :forbidden && return didn't work, while head(:forbidden) && return did
3

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([email protected]? && @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.

Comments

1

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

2 Comments

Yes, I probably have to play with these :status parameters. Thanks!
Well, this is true. However, if I am working on an API in rails, I would need to explicitly mentioned the status code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.