未定义的方法`admin?’ 为零:NilClass

我跟着railscast#250来自Scratch的身份validation并且得到了很好的工作。 现在我只想在我的索引页面上显示编辑和销毁链接给admin用户。

我已经设置了mu用户数据库,其中包含一个admin boolean字段,并尝试在另一个模型(hikingtrails)的视图中放置一个简单的if语句,只显示管理员用户的某些链接,但是当我尝试它时,我得到了这个错误, undefined method 'admin?' for nil:NilClass undefined method 'admin?' for nil:NilClass

数据库架构

  create_table "users", :force => true do |t| t.string "email" t.string "password_digest" t.boolean "admin" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end 

用户模型

 class User  true has_secure_password end 

应用控制器

 class ApplicationController < ActionController::Base protect_from_forgery # fetch the currently logged-in user record to see if the user is currently logged in # putting this method in ApplicationController so that it's available in all controllers private def current_user # checks for a User based on the session's user id that was stored when they logged in, and stores result in an instance variable @current_user ||= User.find(session[:user_id]) if session[:user_id] end # to give access to this method from all the views, the helper_method makes it a helper method helper_method :current_user # basic authorization, user must be logged in! def authorize redirect_to login_url, alert: "You must be logged in to perform this action" if current_user.nil? end end 

视图/ hikingtrails / index.html.erb

    t("helpers.links.edit")), edit_hikingtrail_path(hikingtrail), :class => 'btn btn-mini' %>  t("helpers.links.destroy")), hikingtrail_path(hikingtrail), :method => :delete, :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) }, :class => 'btn btn-mini btn-danger' %>  

如果用户未根据您的代码登录,则current_user将为nil。 所以你需要这样做:

 <% if current_user && current_user.admin? %> 

或使用try方法Rails添加到所有对象。

 <% if current_user.try(:admin?) %> 

正如Dogbert所说,如果用户没有登录, current_user将为nil。

我建议另外两种选择:

1)current_user方法中返回一个特殊类型“guest”用户而不是nil。 如果您希望稍后使用其他内容执行其他操作,例如响应某些用户操作,则Il将非常有用。
作为灵感,看看Ryan Bates如何解释他的gemcancanAbility类: 链接 。 他所做的第一件事就是创建一个统一的(而不是持久的DB)用户。 每次Rails使用这种用户validation解析ERB模板时,都会实例化一个Ability类。
所以,你可以这样做:

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

因此,如果(User.find(session[:user_id]) if session[:user_id])返回nil ,则@current_user将被设置为未初始化的用户,在DB中没有身份。

2)定义一个新的metod只是为了检查用户是否是管理员,例如:

 # your unmodified current_user implementation def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end def is_an_admin? if current_user && current_user.admin? end 

这样你就可以这样使用它:

 <% if is_an_admin? %> 
<%= do stuff....%>

…这可能是一个额外的方法调用,但它也可能使您的代码更具可读性。

我知道这是旧的,但如果有人像我一样搜索错误,Rails教程中实际上没有错误,但是他们忘了强调他们添加的一件事。

代码清单9.54

 before_action :logged_in_user, only: [:index, :edit, :update, :destroy] 

请注意,他们在这里添加了:destroy action,之前没有添加,这确保用户被记录以执行destroy操作,然后检查他是否是管理员

 before_action :admin_user, only: :destroy 

更正:

截至2015年12月14日编辑时,rails教程现在添加了代码清单9.53中的:destroy操作。 如果您像我一样错过了那个,那么您将收到此错误。

它在您的用户模型中看起来像:

  attr_accessible :email, :password, :password_confirmation#, :admin 

管理员已注释掉,您需要删除#。