render/head in before_action does not stop executing the rest of the action

3.4k Views Asked by At

I have a private method authenticate_user! in my application controller which verifies the tokens in the header and returns a user record if found. Here is what it looks like.

def authenticate_user!
  # authenticate
  @current_login = Login.where(oauth2_token: bearer_token).first
  head 401 if @current_login.nil? # and return
  @current_user = @current_login.user
  head 401 if @current_user.nil? 
end

I use this method to authenticate the user in the controllers as follows.

class AddressesController < ApplicationController
   before_action :authenticate_user!

   def some_action
      data = @current_user.some_associated_records
      render json: {data: data}
   end
end

Ideally, when a login is not found or a corresponding user is not found, I should get a 401 response from the authenticate_user! method.

Instead, I always get a 500 internal server error. Somehow the head 401 if current_login.nil? does not halt the execution chain. Even render status: 401 doesn't do the job.

According to my understanding, rails returns if it finds a render or a head command in before_action filter. What is it that I am missing?

Edit:

The following solution works:

      private

      def authenticate_user!(*)
        @current_login = Login.where(oauth2_token: bearer_token).first!
        @current_user = @current_login.user
        rescue ActiveRecord::RecordNotFound
          head 401
      end

However I a still confused why the original approach does not work.

1

There are 1 best solutions below

0
sfate On

As @Rahul mentioned (render/head in before_action does not stop executing the rest of the action) 500's error occurs on the step when you're trying to get a user from @current_login which is nil at this step.

head method just calls render nothing: true with provided status. And render doesn't breaks any execution chain.

According to above notes I'd suggest to rewrite it like this:

def authenticate_user!
  @current_login = Login.find_by(oauth2_token: bearer_token)
  @current_user = @current_login&.user
  head 401 if @current_user.nil? 
end