CanCan中load_and_authorize_resource的解释

24

我想知道 load_and_authorize_resource 在内部是如何工作的。 我查看了 Github 页面 链接 并尝试理解,但没有找到有用的信息。我只知道load_and_authorize_resource就像一个before_filter,并且以某种方式加载我们在 ability.rb 中编写的功能。

我希望更好地了解这个过程。我的意思是,我不想学习整个 gem,而只想查看 cancan 如何在控制器中加载资源的能力,以及load_and_authorize_resource是否真的是一种 before_filter。

1个回答

35

免责声明:为了简单起见,我有意省略了一些内部短方法的调用。完整的调用链可以通过查看load_and_authorize_resource方法定义等来获得。

如文档所述,load_and_authorize_resource设置了一个before_filter...

# cancan/lib/cancan/controller_additions.rb
def load_and_authorize_resource(*args)
  cancan_resource_class.add_before_filter(self, :load_and_authorize_resource, *args)
end

...其中调用了两个方法:load_resourceauthorize_resource

# cancan/lib/cancan/controller_resource.rb
def load_and_authorize_resource
  load_resource
  authorize_resource
end

为了了解它们的行为,我们需要仔细观察它们两个。
基于传递给你的控制器操作的params哈希表,load_resource根据判断是否应该获取一个新的类实例(例如Post.new)还是根据params[:id]查找特定的实例(例如Post.find(params[:id]))。该实例(或者对于像index这样的操作,一组实例)被分配给相应的控制器操作的实例变量。
# cancan/lib/cancan/controller_resource.rb
def load_resource
  unless skip?(:load)
    if load_instance?
      # here you have obtained your object, e.g. Post with id=5
      # and placed it into cancan resource_instance variable.
      # it has automatically set up @post instance variable for you
      # in your action
      self.resource_instance ||= load_resource_instance
    elsif load_collection?
      self.collection_instance ||= load_collection
    end
  end
end

稍后,将调用authorize_resource。它内部的逻辑语法应该对您很熟悉:手动检查权限看起来与此方法内部发生的事情完全相同。基本上,您获取前一步得到的resource_instanceparams[:action](当前操作的名称)以及检查是否可以访问给定对象的特定操作。

# cancan/lib/cancan/controller_resource.rb
def authorize_resource
  unless skip?(:authorize)
    # similar to what happens when you call authorize!(:show, @post)
    @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
  end
end

只要在 before_filter 中抛出异常,就可以停止控制器动作的执行。如果未能通过授权,在这里失败会将您重定向到应用程序的主页 URL,显示500错误页或您为 CanCan::AccessDenied 处理定义的任何行为。

另一方面,如果您已经成功通过授权,您的操作代码将被执行。现在,您可以访问由 CanCanload_resource 步骤中设置的实例变量(例如@post)。


2
它如何知道是获取集合,还是创建或加载实例? - mwfearnley
1
对于 :index 操作,它会加载 @things,但对于其他所有操作,它都会加载 @thing(基于 :id)。 - stevec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接