3

我使用 Devise 进行身份验证,使用 CanCan 进行授权。

目标

我有两个模型:User 和 Sponsorship,其中 Sponsorship 提供了 has_many :through user-as-sponsor 和 user-as-client 之间的关系。

我想配置 CanCan 以便具有sponsor?特权的用户可以管理他或她自己的赞助,也就是说,只有Sponsorship#client_id == user.id. 用户还可以拥有admin?特权,在这种情况下,他或她可以管理任何赞助。

模型

class User < ActiveRecord::Base
  has_many :sponsor_links, :class_name => 'Sponsorship', :foreign_key => 'client_id'
  has_many :sponsors, :through => :sponsor_links, :class_name => 'User'

  has_many :client_links, :class_name => 'Sponsorship', :foreign_key => 'sponsor_id'
  has_many :clients, :through => :client_links, :class_name => 'User'

  def has_role?(role)
    ... return true if this user has <role> privileges
  end
end

class Sponsorship
  belongs_to :sponsor, :class_name => 'User'
  belongs_to :client, :class_name => 'User'
end

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new  # handle guest user (not logged in)
    if user.has_role?(:admin)
      can :manage, :all
    elsif user.has_role?(:sponsor)
      # not sure if the third argument is correct...
      can :manage, Sponsorship, :sponsor => {:user_id => user.id}
    end
  end
end

路线

我设置了嵌套路由来反映赞助用户拥有他或她的客户的事实:

resource :users, :only => [:index]
  resource :sponsorships
end

问题

在我的 SponsorshipsController 中加载和授权用户和赞助资源的正确方法是什么?

我试过的

这类似于 CanCan 轻松处理的普通嵌套资源。但是这些关系具有非标准名称(例如:sponsor_links 而不是:sponsorships),而且我还没有弄清楚如何load_and_authorize_resource在我的 SponsorshipsController 中配置声明。

在我尝试过的许多不起作用的事情中;),这是更简单的版本之一。(另请注意,我的能力可能没有正确设置——见上文):

class SponsorshipsController < ApplicationController
  load_and_authorize_resource :sponsor_links, :class_name => "User"
  load_and_authorize_resource :sponsorships, :through => :sponsor_links
  respond_to :json

  # GET /users/:user_id/sponsorships.json
  def index
    respond_to @sponsorships
  end

  # GET /users/:user_id/sponsorships/:id.json
  def show
    respond_to @sponsorship
  end
end

通过抢救 CanCan::AccessDenied 错误,我知道:

  • index使用:sponsor用户时,用户的身份验证失败。
  • index使用:admin用户时,赞助的身份验证失败。
  • show中,无论角色如何,发起人的身份验证都会失败。
4

1 回答 1

1

部分答案

第一个问题是在能力规范中,内容如下:

...if user.has_role?(:sponsor)
  can :manage, Sponsorship, :sponsor => {:user_id => user.id}
end

但应该只是

...if user.has_role?(:sponsor)
  can :manage, Sponsorship, :user_id => user.id
end

(记住,孩子们,单元测试是你的朋友!不知何故我忘记了那节课。)

在控制器中,我还更改了:

  load_and_authorize_resource :sponsor_links, :class_name => "User"
  load_and_authorize_resource :sponsorships, :through => :sponsor_links

只是

  load_and_authorize_resource :user
  load_and_authorize_resource :sponsorship

主要是有效的:它设置@user 和@sponsorship 并授权访问它们。但是 index 函数会加载 current_user 可以访问的所有赞助,而不仅仅是 :user_id 拥有的赞助。我的修复——可能不是最优的——是从

  def index
    respond_with(@user, @sponsorships)
  end

  def index
    @sponsorships = @sponsorships.where(:sponsor_id => @user.id)
    respond_with(@user, @sponsorships)
  end

有了这些改变,一切都奏效了。

如果有人有更合适的方式来表达这一点,我想知道。

于 2012-04-11T02:55:02.273 回答