Search code examples
rubymemoization

Why is an instance variable used instead of a local variable in a module?


I saw this code for a Ruby on Rails application:

module SessionsHelper
  def current_user
    @current_user ||= User.find_by id: session[:user_id]
  end

  ...
end

Why is an instance variable used instead of a local variable in current_user method? When I change it to a local variable, everything is the same as using an instance variable.

I read that an instance variable can be used in many other classes that include this module. But in this case, they are defined in current_user method for storing the user's value @current_user. How is this used in many other classes?


Solution

  • This roughly means that if @current_user, as an instance variable of global request/response scope (Controller/View/Helpers), has already been defined, use it as current_user. Otherwise, assign it the user that corresponds to the id stored in the session do what you do.

    In other words, this is similar to:

    def current_user
        if @current_user # this will be false in every hit, for the same request
            @current_user
        else
            User.find_by id: session[:user_id]
        end
    end
    

    And this should be enough.

    But then, you may use again current_user in some other part of the code, let's say in the controller, for the same request.

    This means, that current_user will have to hit the DB again (caching aside). And you would like to avoid that, if you can. So, why not store the user in a global instance variable?

    Thus:

    def current_user
        if @current_user # this will be false for the first hit, true for every subsequent request
            @current_user 
        else
            @current_user = User.find_by id: session[:user_id]
        end
    end
    

    And since we do this, why not use the shorthand method for it?

    So, finally:

    def current_user
        @current_user ||= User.find_by id: session[:user_id]
    end
    

    The answer is, you do this for reusability shake, within the same request/response.