Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are instance variables necessary for Rails as API only?

What role to instance variables play in a Rails API? I am building a backend API in Ruby on Rails and I am following Michael Hartl's RoR tutorial. He makes use of instance variables in RoR's templating engine. However, if I am simply using RoR simply as an API, do I still need instance variables?

Below is a snippet from Michael Hartl's tutorial on how to find a current user.

  def current_user
    if (user_id = session[:user_id])
      @current_user ||= User.find_by(id: user_id)
    elsif (user_id = cookies.signed[:user_id]) # User has closed the browser before and persistent session exists
      user = User.find_by(id: user_id)
      if user&.authenticated?(cookies[:remember_token])
        log_in user
        @current_user = user
      end
    end
  end

I am making web requests from a decoupled frontend, would @current_user always be nil to begin wtih? Can I simply user a regular variable instead?

like image 656
Liondancer Avatar asked Feb 01 '26 05:02

Liondancer


2 Answers

As @Mark wrote in the questions, if you don't access the instance variable in a view you can just use a local variable.

I am making web requests from a decoupled frontend, would @current_user always be nil to begin wtih? Can I simply user a regular variable instead?

How do you communicate with your frontend? I assume it does request JSON? Then you need to expose your instance / local variable to your JSON. Something like this:

class UsersController < ApplicationController
  def show
    render json: { current_user: current_user }
  end

  private

  def current_user
    if (user_id = session[:user_id])
      @current_user ||= User.find_by(id: user_id)
    elsif (user_id = cookies.signed[:user_id])
      user = User.find_by(id: user_id)
      if user&.authenticated?(cookies[:remember_token])
        log_in user
        @current_user ||= user
      end
    end
  end
end

Also I think in the example from your tutorial, this method is also used to memoize the current user and don't fetch it again / login again. If you split, it might be more clear:

  def current_user
    @_current_user ||= fetch_current_user
  end

  def fetch_current_user
    if (user_id = session[:user_id])
      User.find_by(id: user_id)
    elsif (user_id = cookies.signed[:user_id]) # User has closed the browser before and persistent session exists
      user = User.find_by(id: user_id)
      if user&.authenticated?(cookies[:remember_token])
        log_in user
        user
      end
    end
  end

Now we store the current user in current_user and don't log it in again or fetch it again from the database (https://en.wikipedia.org/wiki/Memoization). For instance, if you need to do a authentication / authorization check you need to access current_user several times.

class UsersController < ApplicationController
  before_action :check_user

  def show
    render json: { current_user: current_user }
  end

  private

  def check_user
    return unless current_user.admin?

    render json: {}, status: 404
  end
end

Edit

A convention which is often used to indicate that the instance variable is not directly used but only for memoization is to prefix with an underscore.

def current_user
  @_current_user ||= fetch_current_user
end

def fetch_current_user; end

The memoization in Ruby is done with ||= which evaluates to @_current_user || @_current_user = fetch_current_user, so @_current_user is only set if @_current_user is logically false. So if a is already set, we don't need to fetch it again and just use the value stored in the instance variable.

like image 67
Christian Bruckmayer Avatar answered Feb 02 '26 22:02

Christian Bruckmayer


If you don't have any views and the instance variable isn't used anywhere else in the class (or any classes that inherit from this class), then you can replace them with local variables.

Instance variables are used to either have access to that variable from any instance method within the class, or to expose the variable to a view file.

like image 35
Mark Avatar answered Feb 02 '26 22:02

Mark