2010-11-13 69 views
12

我目前正在通过RoR教程(http://railstutorial.org/chapters/sign-in-sign-out#sec:signin_success是相关部分),这似乎是相当不错的,虽然我在尝试查看示例站点时遇到以下问题。未定义的本地变量或方法'current_user'

Extracted source (around line #10): 

7:   <li><%= link_to "Home", root_path %></li> 
8:   <li><%= link_to "About", about_path %></li> 
9:   
10:    <% if signed_in? %> 
11:     <li><%= link_to "Profile", current_user %></li> 
12:     <li><%= link_to "Sign out", signout_path, :method => delete %></li> 
13:    <% else %> 

正如你所看到的,这个问题从我的方法而产生“signed_in?”这是为了检查用户是否登录或不通过检查CURRENT_USER变量是否被设置(我已经包括从助手的代码的其余部分给一个背景下,道歉):

module SessionsHelper 

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

    def sign_out 
    cookies.delete[:remember_token] 
    current_user = nil 
    end 

    def current_user= (user) 
    @current_user ||= user_from_remember_token 
    end 

    def signed_in? 
    !current_user.nil? 
    end 

    private 

    def user_from_remember_token 
     User.authenticate_with_salt(*remember_token) 
    end 

    def remember_token 
     cookies.signed[:remember_token] || [nil, nil] 
    end 

end 

从我的理解,。尼尔?是一种检查对象是否已被定义的方法,因此未定义的对象不应该生成错误而是返回false?我搜索了教程中关于current_user的所有案例(在检查是否有其他人有这个问题,并且没有成功之前),我的代码看起来是正确的,所以我有点困惑,如果有人能够帮助我理解Ruby变量的方式应该被访问,为什么我的代码不工作,我会非常感激。

编辑:

我不知道这是否与范围的重要,因为我刚开始都Rails和Ruby的,但助手SessionsHelper正在使用我的用户控制器和视图(它包含在我的应用程序控制器)

回答

7

我跑到这个相同的问题&这是出于同样的原因。您忽略了“代码清单9.16”中的部分指示。

def current_user= (user) 
    @current_user ||= user_from_remember_token 
end 

你应该改变以下内容。

def current_user 
    @current_user ||= user_from_remember_token 
end 

您还需要将* self。* current_user的所有实例更改为* @ * current_user。

一旦你这样做了错误(s)解决。

2

零?方法不会检查是否定义了变量或方法。它只是检查它是否被定义为无对象。 Ruby走上了SessionsHelper的祖先链,最终确定current_user没有被定义在任何地方(它最终会在Kernel#method_missing结束),然后抛出一个错误。解决问题的最快方法是:

#app/helpers/sessions_helper.rb 
def current_user 
    @current_user ||= false 
end 
+0

或者我相信你可以做“@current_user || = user_from_remember_token || false”,如果你想更符合你当前的代码。 – JackCA 2010-11-13 14:47:14

+0

虽然这肯定会阻止错误,但它会不断返回错误。我想这可能会导致我的签名方法出现问题,导致current_user永远无法定义,所以最好让我在睡个好觉之后再看看它。 – djlumley 2010-11-13 14:49:07

2

我问了一个朋友,他纠正了我的错误。我认为我的错误的很大一部分来自于不完全熟悉Ruby中的变量作用域,并忘记了一切都是对象,因此current_user =(user)方法正在重写赋值函数。

我的朋友的解决方案是将current_user的范围更改为实例化变量(因此可以正确使用),并将函数curent_user =(user)更改为简单的get_current_user函数以确定当前用户是否存在在cookie中。

最终改变的代码如下:

#app/helpers/sessions_helper.rb 

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

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

    def get_current_user 
    @current_user ||= user_from_remember_token 
    end 

    def signed_in? 
    !get_current_user.nil? 
    end 

#app/views/layouts/_header.erb 
<% if signed_in? %> 
       <li><%= link_to "Profile", get_current_user %></li> 
       <li><%= link_to "Sign out", signout_path, :method => :delete %></li> 
      <% else %> 
       <li><%= link_to "Sign in", signin_path %></li> 
      <% end %> 

正如你可以看到在我的报头部分的变量也被改变,以反映在所述助手用来获得用户的方法。

要开始阅读一些基本的Ruby导杆,下一次我在我头上我从哪里开始修复它:)

+1

Rails授权的最佳实践是命名方法current_user而不是get_current_user并定义方法current_user?检查current_user是否为零。这是一种非常普遍的模式。 – 2010-11-14 14:48:09

+0

有特别的理由吗?还是像大多数Rails的情况一样,仅仅因为人们是这样做的?我可以看到增加了可读性,只是想知道是否有另一个我失踪的原因。 – djlumley 2010-11-14 20:59:41

+0

这不仅仅是一个Rails的东西。 getter和setter的Ruby约定是attribute_name()和attribute_name =()。添加的能力?到方法名称是故意的,以便开发人员可以形成一致的问题。 Ruby被设计为尽可能地对话。 – 2010-11-17 13:16:11

4

请确保您有下面的代码在SessionHelper

的想法
def current_user=(user) 
    @current_user = user 
end 

def current_user 
    @current_user ||= user_from_remember_token 
end