啊,伙计-我应该工作而不是回答有关SO的问题...
TLDR;变量没有被设置,这@user
就是你的代码很奇怪的原因。
您将资源与访问它的人混为一谈
让我来看看你的第一个用例并解释发生了什么:
# Case 1
class UsersController < ApplicationController
def index
authorize! :index, @user, :message => 'Not authorized as an administrator.'
@users = User.all
end
end
你已经有真正的(但令人困惑的)错误
在这个阶段你实际上有一个错误。您在访问资源的人current_user
与您授予他们访问权限的资源之间感到困惑,即@user
. 我是 Peter ( current_user
),但我可能正在尝试访问 John 的 ( @user
) 用户页面。John 是我请求访问的资源。
在您的代码中,您实际上并没有加载您想要授予访问权限的资源。让我一步一步分解发生了什么。
我将使用 show 动作,因为它更容易看到正在发生的事情,但同样的事情也index
适用
假设我,彼得正在尝试访问您的(鲶鱼)页面:
class UsersController < ApplicationController
def show
# first let's get explicit about who's accessing the page
@current_user = current_user
# now we need to load up the page I'm trying to access
@user = User.find params[:id]
# can I, Peter, access the :show action of this profile?
authorize! :show, @user, :message => 'Not authorized as an administrator.'
# rest of your controller...
@users = User.all
end
end
这会加载我,current_user
然后加载您,@user
然后询问我是否有权访问您的:show
操作。
你的情况发生了什么
您正在使用 index 操作这一事实令人倍感困惑,因为那里没有任何资源可供加载。因此,我将解释使用 show 操作发生了什么:
# case 1
# this requests access FOR current_user TO @user
# I have no idea what the value of @user is (probably nil)
def show
authorize! :show, @user, :message => 'Not authorized as an administrator.'
@users = User.all
end
# case 2
# this requests access FOR current_user TO current_user
def show
# this is not what you want
authorize! :show, current_user, :message => 'Not authorized as an administrator.'
@users = User.all
end
# case 3)
# This requests access FOR current_user TO @my_user
# I have no idea what the value of @my_user is (probably nil)
def show
authorize! :show, @my_user, :message => 'Not authorized as an administrator.'
@users = User.all
end
您需要先加载资源并将该资源传递给能力文件
您当前的用户是通过该authenticate_user!
方法为您加载的。但是,您需要确保您尝试访问的资源也已加载。在:show
行动的情况下,这将像这样发生:
class UsersController < ApplicationController
def show
# load the resource you want to protect access to
@user = params[:id]
# use cancan to see whether anyone can access it
authorize! :show, @user
@users = User.all
end
end
但是,根据这是否是嵌套资源的最后一层,资源的 id 可能是id
或user_id
。在:index
动作中根本不会有这些参数中的任何一个。所有这一切都很痛苦,但是 cancan 可以很好地为您使用load_resource
class UsersController < ApplicationController
def show
# CanCan figures out that the resource is a User and then gets it using the params
load_resource
# @user is now set.
# If the URL is http://yoursite.com/users/5, then @user.id == 5
authorize! :show, @user
@users = @user # not actually necessary since load_resource has already done this
end
end
现在,cancan 通过结合加载和授权步骤使其变得更加容易
class UsersController < ApplicationController
def show
# figures out what you want to load and authorizes it (sweet)
load_and_authorize_resource
# @user will now be equal to User.find(params[id])
# no need to load @user - it's already been done
end
end
最后,您可以将它们提取到 before_filter 中,这样您就不必编写它们了
class UsersController < ApplicationController
before_filter load_and_authorize_resource :user
def show
# in a pure CRUD app you literally won't need any code in your show action
end
end
使这一切更容易理解的方法
不要使用用户资源来学习 cancan 使用页面、文章或其他任何内容。它将帮助您清楚哪个部分是资源,@page
哪个部分是当前用户@current_user
不要在索引操作上学习索引操作实际上不会加载特定资源,因为没有要加载的资源。这再次使事情变得更加难以理解。查看正在发生的事情:show
或:edit
然后转到不占用资源的操作 ( :new
, :index
, :create
)