5

我无法理解 Michael Hartl 编写的 Ruby on Rails 教程中“记住我”的实现。他创建了一个带有登录方法的 SessionsHelper 模块,其中包含以下内容:

module SessionsHelper

    def sign_in(user)
        cookies.permanent.signed[:remember_token] = [user.id, user.salt]
        current_user = user
    end

    def current_user=(user)
        @current_user = user
    end

    def current_user
        return @current_user ||= user_from_remember_token
    end

    private
        def user_from_remember_token
            #passes array of length two as a parameter -- first slot contains ID,
            #second contains SALT for encryption
            User.authenticate_with_salt(*remember_token)
        end

        def remember_token
            #ensures return of a double array in the event that
            #cookies.signed[:remember_token] is nil.
            cookies.signed[:remember_token] || [nil,nil]
        end

end

注意: authenticate_with_salt User 模型中的方法通过第一个参数(id)找到用户,如果定义了用户并且其 salt 等效于第二个参数(salt),则返回用户,否则返回 nil。

我无法理解为什么我们要花这么多时间来测试用户是否已经登录:

如果用户已登录,@current_user则该方法已定义,sign_in因此该方法中的 ||=current_user没有意义。

如果用户未登录,该方法中的 ||= 运算符将返回该current_user方法返回的值user_from_remember_token,但由于 cookies.signed[:remember_token] 将为 nil,User.authenticate_with_salt因此将传递 [nil,nil] 参数并且将返回 nil,因此该current_user方法将返回 nil。

简而言之,如果该current_user方法返回 @current_user(如果它已定义,则返回 nil),那么仅使用传统的访问器方法会不会更简单:

def current_user
    return @current_user
end

Michael Hartl 的书说这样做是没有用的,因为用户的登录状态会被遗忘。为什么会这样???有人可以解释为什么我们不这样做,而是使用上面发布的更复杂的版本吗?

4

2 回答 2

2

sign_in仅在您使用登录表单实际登录时调用。之后,您必须使用每个请求的 cookie 值设置当前用户。

因此,当用户登录并打开页面时,第一次current_user调用它将填充@current_user实例变量并将其用于进一步current_user调用。

于 2011-06-22T13:23:35.613 回答
2

线

return @current_user ||= user_from_remember_token

是惰性初始化的一种形式,以避免在@current_user实际需要之前初始化变量。 @current_user第一次调用此函数时永远不会初始化,但在每次连续调用时都会有一个值(假设user_from_remember_token返回非 nil 的值)。

他本可以写

def current_user
  return user_from_remember_token
end

此代码将始终将当前用户初始化为它从 cookie 中读取的任何内容。这将正常运行,但他可能想避免重复读取 cookie,因此他只读取一次并将其存储在变量中。

他做不到

def current_user
  return @current_user
end

因为 @current_user 变量不会在页面请求中持续存在。在页面呈现并发送回客户端后,@current_user 变量被销毁并且其值被遗忘。

希望这可以帮助。查看维护 Web 应用程序中的状态,以获取有关为什么有必要跳过这些障碍的更多信息。

于 2011-06-22T16:00:05.063 回答