Ruby - rails - 用户模型上的NoMethodError

时间:2012-05-02 03:33:20

标签: ruby ruby-on-rails-3

我正在为current_user.user_id获取此NoMethodError。下面是我的用户模型表。我不知道该错误意味着什么,因为current_user.user_id存在。什么可能导致这个问题?我迷失在这里。据我所知,我没有收到这个错误,我一直在为项目添加新东西,而且我搞砸了。虽然我正在进行与用户模式无关的更改。之后为什么NoMethodError如果有current_user.user_id?无能和困惑。

错误 -

Started GET "/item/list" for 10.10.10.10 at 2012-05-01 23:19:19 -0400
Processing by Item#list as */*
Completed 500 Internal Server Error in 0ms

NoMethodError (undefined method `user_id' for nil:NilClass):
  app/controllers/Item_controller.rb:52:in `list'

用户模型表 -

mysql> explain users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| user_id    | varchar(255) | YES  |     | NULL    |                |
| name       | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

使用current_user.user_id的项目控制器 -

    def list
    @mylist = Item.find(:all, :select => 'item_num', :conditions => { :id => current_user.user_id, :item_status => ["New"]} )
    respond_to do |format|
    format.html { render :partial => 'item_list'}
    format.js
    end
    return @mylist
    end


    def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
    end

    def debug
    render :text => current_user.user_id #prints correct user_id
    end

3 个答案:

答案 0 :(得分:3)

当您尝试在其上调用current_user时,错误消息告诉您nil设置为user_id。根据您提供的代码,我无法告诉您为什么current_usernil,但如果您可以追踪current_user分配用户的方式/位置,那就是您要去的地方找到你的问题。它与您的数据库没有任何关系。

答案 1 :(得分:2)

问题似乎不是您的用户模型没有响应方法user_id,但根据错误消息,方法current_user返回nil,而nil不响应user_id。所以原因可能是即使没有任何用户登录也可以调用此操作。

解决这个问题的一种方法是首先检查current_user在调用user_id之前是否返回任何内容。也许是这样的:

@mylist = Item.find(:all, :select => 'item_num', :conditions => { :id => (current_user && current_user.user_id), :item_status => ["New"]} )

如果curret_user为nil,它将评估为false,然后不会调用user_id,而是查询id为NULL的Items。如果这是您的应用的适当行为,我会留给您。

作为旁注,你的语法不是真正的Rails 3.我会改为:

@mylist = Item.select(:item_num).where(:id => (current_user && current_user.user_id), :item_status => ["New"])

答案 2 :(得分:2)

你得到这个是因为current_user正在变为零。您当前的用户功能没有按照您的想法执行,让我们来看看:

def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
end

所以,这按此顺序执行:

  1. 如果有session[:user_id],请继续|或者返回nil

  2. 然后,如果设置了@current_user,则返回@current_user |或者继续

  3. 然后,将@current_user设置为User.find(session[:user_id])

  4. 注意:User.find()如果无法找到用户,则会引发异常。 User.find_by_user_id()只会返回nil而不会引发异常。请务必选择您想要的行为。

    您的方法还可以,这意味着只要未设置nil,您就会获得session[:user_id]。您只需要在代码中捕获它。因为nil是假的,所以这很容易。在任何红宝石代码中:

    any_method if current_user
    

    在您的控制器中,您需要执行以下操作:

    def list
      if current_user
        @mylist = Item.find(:all, :select => 'item_num', :conditions => { :id => current_user.user_id, :item_status => ["New"]} )
        respond_to do |format|
          format.html { render :partial => 'item_list'}
          format.js
        end
      else
        redirect_to login_path, :notice => "You must be logged in to continue."
      end
    end
    

    注意(1)在Ruby中你不需要说return,每个方法的最后一行都是自动返回的,(2)Rails控制器方法在重定向或渲染时结束,没有返回。

    为了使这个更干净,我可能会说你需要一个before_filter。控制器中的这样的东西应该可以解决这个问题:

    before_filter :require_login
    
    def require_login
      redirect_to login_path, :message => 'You must be logged in to view this page.' unless current_user
    end
    

    如果他们尚未登录,那么您的所有方法都会将此人重定向到登录状态。您还可以使用:only或:except选项仅指定某些方法来使用此过滤器。

    由于您可能会在整个应用中使用该方法,因此可能会将current_userrequire_login方法移至应用程序控制器。

    最后一点,您的代码和您的问题反映出您不熟悉rails和REST的一些基本概念。如果你学习做事的“Rails方式”,你真的会加快你的发展。迈克尔·哈特尔Rails 3 Tutorial是一个很好的免费资源,可以让你走上正轨。你应该通过它,你会很高兴你做到了,当你完成后,你将超越你现在的位置。