1

I am in section 8.4.3 - Forgetting Users of the Rails Tutorial.

# app/helpers/session_helper.rb
module SessionsHelper
...
  # Returns the user corresponding to the remember token cookie.
  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 && user.authenticated?(cookies[:remember_token])
        log_in user
        @current_user = user
      end
    end
  end

  # Logs out the current user
  def log_out
    forget(current_user)
    session.delete(:user_id)
    @current_user = nil
  end
...
end

In the current_user method we assign a user to the @current_user instance variable. I don't understand why we don't use that same instance variable in the log_out method (in that method current_user is not prepended with an @ symbol). Where does current_user come from then since it isn't passed in as an argument to that method?

3
  • 2
    current_user is a helper method github.com/plataformatec/devise#controller-filters-and-helpers Commented Jun 3, 2015 at 13:23
  • 2
    forget(current_user) it is calling helper current_user. Ruby methods default return last executed line. So current_user helper will return @current_user object if user logged_id. Commented Jun 3, 2015 at 13:28
  • 1
    Another important to note here is that @current_user is not set until you call the current_user method. So in the scope of the log_out method, you have to assume @current_user doesn't exist until you run the method that creates it, which is current_user. Commented Jun 3, 2015 at 13:45

2 Answers 2

1

Ruby doesn't make difference between a method invocation and a local variable. That is the reason why current_user might look like both. In your case it's the defined method.

You can actually use both @current_user and current_user as the returned value of that method should be equal to @current_user.

Sign up to request clarification or add additional context in comments.

Comments

1

current_user is the method defined at the snippet you posted of the page.

@current_user is the instance variable set BY current_user

So when you look at the code:

# Defines a method called log_out
def log_out
  # Calls the 'forget' method on the result of the 'current_user' method,
  #   which sets @current_user
  forget(current_user)
  # Deletes the session variable named 'user_id'
  session.delete(:user_id)
  # Resets @current_user to nil, because there should no longer be one
  @current_user = nil
end

If I wanted to look at it differently, I could say:

def log_out
  # Sets @current_user
  current_user
  # Calls the forget method on the variable @current_user
  forget(@current_user)
  session.delete(:user_id)
  @current_user = nil
end

But I could NOT change the last line to current_user = nil instead of @current_user = nil, because then I am assigning the nil value to the name of a method instead of to the instance variable.

Part of the reason method calls and variables look so similar in Ruby is that everything is handled as an object, so methods are essentially just a variable whose value is a block of code (there are technical differences to what we call a "block" and a method, but conceptually this is a decent analogy). When we define a method, we save it into what is, more or less, a variable. Thus if we think about the method "current_user", we may instead think of it as a variable "current_user" whose value is forget(current_user); session.delete(:user_id); @current_user=nil.

This is an oversimplification, of course, but it is worth keeping in mind as you go forward with your learning.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.