Rails——“记住我”能力

发布于 2024-11-16 16:38:41 字数 1706 浏览 10 评论 0原文

我无法理解 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

注意: User 模型中的 authenticate_with_salt 方法通过第一个参数( id),如果定义了用户并且其盐相当于第二个参数(盐),则返回用户,否则返回 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 的书说这样做会是无用,因为用户的登录状态会被忘记。为什么会这样???有人可以解释一下为什么我们不这样做而是使用上面发布的更复杂的版本吗?

I am having trouble understanding the implementation of "Remember Me" in the Ruby on Rails Tutorial by Michael Hartl. He creates a SessionsHelper module with methods for signing in, containing the following:

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

NOTE: The authenticate_with_salt method in the User model finds the user by the first parameter (the id) and if the user is defined and its salt is equivalent to the second parameter (the salt) then the user is returned, otherwise nil is returned.

I am having trouble understanding why we go to such lengths to test if the user has already been signed in:

In the event that the user is signed in, @current_user is already defined by the sign_in method and therefore the ||= in the current_user method is meaningless.

In the event that the user is not signed in, the ||= operator in the current_user method returns the value returned by the user_from_remember_token method, but since cookies.signed[:remember_token] would be nil, User.authenticate_with_salt would be passed the [nil,nil] argument and would return nil, and therefore, the current_user method would return nil.

In short, if the current_user method is returning @current_user if it is defined and nil otherwise, wouldn't it be much simpler to just use the conventional accessor method:

def current_user
    return @current_user
end

Michael Hartl's book says that doing this would be useless because the user's sign in status would be forgotten. Why would that be the case??? Can someone please explain why we do not do this and instead use the much more intricate version posted above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苏佲洛 2024-11-23 16:38:42

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

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

sign_in is only called when you actually sign in using the login form. After that you have to set the current user using the cookie values for each request.

So when the user is signed in and opens a page, first time current_user is called it will populate the @current_user instance variable and use it for further current_user calls.

月依秋水 2024-11-23 16:38:41

该行

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 应用程序中的状态,以获取有关为什么需要跳过这些障碍的更多信息。

The line

return @current_user ||= user_from_remember_token

is a form of lazy initialization to avoid initializing the @current_user variable until it is actually needed. @current_user will never be initialized the first time this function is called, but it will have a value on each successive call (assuming user_from_remember_token returns something other than nil).

He could have written

def current_user
  return user_from_remember_token
end

This code will always initialize the current user to whatever it reads from the cookie. This would behave correctly, but he probably wanted to avoid repeatedly reading the cookie, so he does it once and stores it in a variable.

He cannot do

def current_user
  return @current_user
end

because the @current_user variable does not persist across page requests. After the page renders and is sent back to the client, the @current_user variable is destroyed and its value is forgotten.

Hope this helps. Look into maintaining state in web applications for more information on why it's necessary to jump through these hoops.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文