免责声明:为了简单起见,我有意省略了一些内部短方法的调用。完整的调用链可以通过查看load_and_authorize_resource
方法定义等来获得。
如文档所述,load_and_authorize_resource
设置了一个before_filter
...
def load_and_authorize_resource(*args)
cancan_resource_class.add_before_filter(self, :load_and_authorize_resource, *args)
end
...其中调用了两个方法:load_resource
和authorize_resource
。
def load_and_authorize_resource
load_resource
authorize_resource
end
为了了解它们的行为,我们需要仔细观察它们两个。
基于传递给你的控制器操作的params哈希表,load_resource根据判断是否应该获取一个新的类实例(例如Post.new)还是根据params[:id]查找特定的实例(例如Post.find(params[:id]))。该实例(或者对于像index这样的操作,一组实例)被分配给相应的控制器操作的实例变量。
def load_resource
unless skip?(:load)
if load_instance?
self.resource_instance ||= load_resource_instance
elsif load_collection?
self.collection_instance ||= load_collection
end
end
end
稍后,将调用authorize_resource
。它内部的逻辑语法应该对您很熟悉:手动检查权限看起来与此方法内部发生的事情完全相同。基本上,您获取前一步得到的resource_instance
、params[:action]
(当前操作的名称)以及检查是否可以访问给定对象的特定操作。
def authorize_resource
unless skip?(:authorize)
@controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
end
end
只要在 before_filter
中抛出异常,就可以停止控制器动作的执行。如果未能通过授权,在这里失败会将您重定向到应用程序的主页 URL,显示500错误页或您为 CanCan::AccessDenied
处理定义的任何行为。
另一方面,如果您已经成功通过授权,您的操作代码将被执行。现在,您可以访问由 CanCan
在 load_resource
步骤中设置的实例变量(例如@post
)。
:index
操作,它会加载@things
,但对于其他所有操作,它都会加载@thing
(基于:id
)。 - stevec