Search code examples
ruby-on-railsrabl

Rails RABL: how to respond with specified http status code?


Basically I have the following controller method:

  def create
    begin
      @check_in = create_check_in()
    rescue => exception
      render json: { message: exception }, status: 500
    end
  end

and the following json.rabl file:

object @check_in => :event_check_in
attributes :id

What I try to achieve is to set manually the HTTP status code of the response. It currently responds with 200, and I need it to be 201 instead.

I saw very few similar question and the answer was generally to render / respond_with from the controller action, so I tried something like this:

  def create
    begin
      @check_in = create_check_in()
      render @check_in, status: 201
    rescue => exception
      render json: { message: exception }, status: 500
    end
  end

but all my attempts failed, throwing various errors.

Is there a way I could set the status code?


Solution

  • The issue is you're passing in @check_in as the first argument of the render method when it expects the first argument to be a hash of options, including the status option.

    Your status: 201 option is being passed in as a hash to the methods second argument and being ignored.

    Typicallya render call will look something like:

    render json: @check_in.as_json, status: 201
    # or more commonly something like
    render action: :create, status: 201 # the @check_in variable is already accessible to the view and doesn't need to be passed in
    # or just
    render status: 201
    # since by default it will render the view with the same name as the action - which is `create`.
    

    There are lots of ways to call render, see the docs for more.

    -- EDIT -- Max has a great comment - I'd strongly advise against rescuing from all exceptions and also against doing it in a specific controller action. In addition to his suggestion, Rails 5+ supports :api formatting for exceptions out of the box or, if you need more, I'd look at a guide like this one.