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?
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With