5

从 Scratch 遵循 railscast #250 Authentication并且一切正常。现在我试图只在我的索引页面上显示编辑和销毁链接到管理员用户的链接。

我已经使用管理员布尔字段设置了 mu User 数据库并尝试在另一个模型(hikingtrails)的视图中放置一个简单的 if 语句,以仅显示指向管理员用户的某些链接,但是当我尝试它时出现此错误,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 < ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation#, :admin

  validates :email, :uniqueness => 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

意见/远足径/index.html.erb

  <% if current_user.admin? %>
    <%= link_to t('.edit', :default => t("helpers.links.edit")),
              edit_hikingtrail_path(hikingtrail), :class => 'btn btn-mini' %>
    <%= link_to t('.destroy', :default => 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' %>
  <% end %>
4

4 回答 4

17

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

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

或者使用tryRails 添加到所有对象的方法。

<% if current_user.try(:admin?) %>
于 2013-04-06T19:39:02.037 回答
5

正如 Dogbert 所说,current_user如果用户未登录,它将为零。

我会建议另外两种选择:

1)current_user方法中返回一个特殊类型的“guest”用户而不是 nil。如果您以后想用它做其他事情,例如响应某些用户操作,Il 将很有用。
作为灵感,看看 Ryan Bates 如何解释Ability他的 gem cancan类:链接。他做的第一件事是创建一个统一的(而不是持久化的)用户。Ability每次 Rails 使用这种用户验证解析 ERB 模板时,都会实例化一个该类。
所以,你可以这样做:

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则将设置为未初始化的用户,在数据库中没有身份。

2)定义一个新的方法来检查用户是否是管理员,例如:

# 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? %>
  <div>
    <%= do stuff....%>

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

于 2013-04-06T20:16:29.373 回答
2

我知道这是旧的,但如果有人像我一样在谷歌上搜索错误,Rails 教程中实际上没有错误,但他们忘记突出显示他们添加的一件事。

清单 9.54

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

请注意,他们在此处添加了 :destroy 操作,之前未添加,这确保用户已登录以执行销毁操作,然后检查他是否是管理员

before_action :admin_user,     only: :destroy

更正:

截至 2015 年 12 月 14 日编辑时,rails 教程现在在清单 9.53 中添加了 :destroy 操作。如果你像我一样错过了那个,你会得到这个错误。

于 2015-07-05T13:17:04.297 回答
-3

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

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

admin被注释掉了,你需要删除#。

于 2013-04-06T19:40:21.310 回答