2

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?

  • 1
    If you want to customize the error responses in rails you can do it by setting `config.exceptions_app` - you can follow the tutorials for [custom error pages](https://web-crunch.com/posts/custom-error-page-ruby-on-rails). If you want to handle specific errors on a per controller level (like for example ActiveRecord::RecordNotFound) you can use `rescue_from`. `rescue => exception` is an antipattern known as pokemon exception handling and should not be used as it will eat anything and make debugging hell. – max Aug 25 '21 at 17:32
  • What is `@check_in` and what are you trying to render? (e.g. json, a .erb view, etc) – melcher Aug 25 '21 at 17:47

1 Answers1

2

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.

melcher
  • 1,543
  • 9
  • 15
  • Thank you both melcher & max for your answers. I think in my situations render status: 201 would be the most suitable approach and it worked finally :) As for error handling, I do actually have a more specific error handling (some custom exception classes: ResourceNotFound, UnauthorizedAction etc,) and call rescue => exception only as a last resort, for reporting internal server errors. I just wanted to only include the essential part in stack overflow, the part that mattered in the context of the question (i.e. the status code), – Alexandru Robert Aug 25 '21 at 18:18
  • 1
    Even in that case you should do it on the framework level so that you log the error and don't just stuff it down a black hole. – max Aug 25 '21 at 19:36