0

I'm working through the RoR tutorial by Michael Hartl. Here's some code from SessionsHelper:

module SessionsHelper                                                       
  def sign_in(user)                                                         
    cookies.permanent[:remember_token] = user.remember_token                
    self.current_user = user                                                
  end                                                                       

  def current_user=(user)                                                   
    @current_user = user                                                    
  end                                                                       

  def current_user                                                          
    @current_user ||= User.find_by_remember_token(cookies[:remember_token]) 
  end                                                                       

  def current_user?(user)                                                   
    user == current_user                                                    
  end                                                                       

  def signed_in?                                                            
    !current_user.nil?                                                      
  end                                                                       

  def sign_out                                                              
    self.current_user = nil                                                 
    cookies.delete(:remember_token)                                         
  end                                                                       

end   

There are a number of things I don't understand from this code.

  • In the method current_user?, is current_user a variable or is it an invocation of the method current_user?

I don't understand how to determine the value of current_user in this context.

  • In the method current_user, @current_user is an instance variable. What is it an instance variable of (i.e. what class?)?

If you look under the sign_in(user) method, you can see that self.current_user is assigned the value of the object user. But (assuming self is of the class UsersController because UsersController < ApplicationController and in the definition of ApplicationController there is a line that include SessionsHelper) there is no definition of an instance variable current_user for the self object.

  • How come in current_user= we use the @current_user but in current_user? we just use current_user?

I've done h the prerequisite searching on StackOverflow but haven't found a good explanation for all these differences. A big part of what I'm trying to learn is when to use @current_user, current_user, :current_user. I'm most familiar with C, C++, PHP, Java, JavaScript. If there are analogues to these languages, it would help me understand better what's going on.

4

3 回答 3

2

In the method current_user?, is current_user a variable or is it an invocation of the method current_user?

It's the method, since there's no lexical of that name in scope.

In the method current_user, @current_user is an instance variable. What is it an instance variable of (i.e. what class?)?

It's an instance variable of an instance of any class which has mixed-in module SessionsHelper (typically with include SessionsHelper).

If you look under the sign_in(user) method, you can see that self.current_user is assigned the value of the object user. But (assuming self is of the class UsersController because UsersController < ApplicationController and in the definition of ApplicationController there is a line that include SessionsHelper) there is no definition of an instance variable current_user for the self object.

sign_in is defined in this module along with a setter method current_user=. self.current_user = user will send the message :current_user= with argument user to self. Since sign_in came from this module it's quite likely that that message dispatch will go to the setter also defined in this module, though it's certainly possible that a setter of the same name may be defined by the class which included this module, or by a module included after this module, in which case those methods will be found first in the dispatch search.

How come in current_user= we use the @current_user but in current_user? we just use current_user?

It's considered good practise to limit direct instance variable access to the setter and getter methods (and sometimes the initialize) when they are defined. In this case, by reusing the current_user getter in the current_user? predicate we preserve the cache or fetch behaviour of the @current_user ||= User.find_by... expression in the getter.

于 2012-10-12T05:07:57.140 回答
2

Just to complement the other answers:

In the method current_user, @current_user is an instance variable. What is it an instance variable of (i.e. what class?)?

Instance variables don't belong to classes. They belong to instances, that's why they are called instance variables. They always belong to self, i.e. whichever object the receiver of the message is.

Instance variables spring into existence magically, the first time they are assigned, they aren't declared anywhere.

于 2012-10-12T08:38:47.007 回答
1

This is a basic concept in object-oriented programming called encapsulation. You have a variable @current_user, but you don't use the variable directly. You use it through methods called getters and setters. Getters for getting the value of the variable en setters for setting the value of a variable.

In this case the getter method is current_user and the setter method is current_user=. Only inside the getter and setter you use the variable @current_user directly. Outside those methods you always use the method call.

于 2012-10-12T05:09:27.793 回答