0

我正在编写一个网络应用程序来从更大、完整的卡片组中随机选择卡片列表。我有一个 Card 模型和一个 CardSet 模型。两种模型都有完整的 RESTful 集 7 个操作(:index、:new、:show 等)。CardSetsController 有一个用于创建随机集的额外操作::random.

# app/models/card_set.rb
class CardSet < ActiveRecord::Base
  belongs_to :creator, :class_name => "User"
  has_many :memberships
  has_many :cards, :through => :memberships

# app/models/card.rb
class Card < ActiveRecord::Base
  belongs_to :creator, :class_name => "User"
  has_many :memberships
  has_many :card_sets, :through => :memberships

我添加了用于身份验证的设计和用于授权的 CanCan。我有具有“编辑”角色的用户。允许编辑器创建新的 CardSet。来宾用户(未登录的用户)只能使用:index:show操作。这些授权按设计工作。编辑器目前可以毫无问题地同时使用:random和动作。:new正如预期的那样,来宾用户不能。

# app/controllers/card_sets_controller.rb
class CardSetsController < ApplicationController
  before_filter :authenticate_user!, :except => [:show, :index]
  load_and_authorize_resource

我想允许来宾用户使用该:random操作,但不允许该:new操作。换句话说,他们可以看到新的随机集,但不能保存它们。操作视图上的“保存”按钮对:random来宾用户隐藏(按设计)。问题是,该:random操作所做的第一件事是构建 CardSet 模型的新实例来填充视图。当 cancan 尝试load_and_authorize_resource一个新的 CardSet 时,它会抛出一个 CanCan::AccessDenied 异常。因此,视图永远不会加载,并且会为来宾用户提供“您需要先登录或注册才能继续”消息。

# app/controllers/card_sets_controllers.rb
def random
  @card_set = CardSet.new( :name => "New Set of 10", :set_type => "Set of 10" )

我意识到我可以通过传递给呼叫来告诉我load_and_authorize_resource跳过该:random动作,但出于某种原因:except => :random,这只是感觉“错误” 。

这样做的“正确”方法是什么?我应该在不实例化新 CardSet 的情况下创建新的随机集吗?我应该继续添加例外吗?

更新

我没有在上面包括我的能力课程。我已对其进行了更新以包含 ':random' 操作,但它仍然无法正常工作。

class Ability
  include CanCan::Ability

  def initialize( user )
    user ||= User.new # User hasn't logged in

    if user.admin?
      can :manage, :all if user.admin?
    else
      # All users, including guests:
      can :read, [Card, CardSet]
      can :random, CardSet

      # All users, except guests:
      can :create, [Card, CardSet] unless user.role.nil?
      can :update, [Card, CardSet] do |c|         
        c.try( :creator ) == user || user.editor?
      end

      if user.editor?
        can [:create, :update], [Card, CardSet]
      end
    end
  end
end
4

2 回答 2

3

我发现了我的问题。CanCan 根本不是问题!我的 CardSet 控制器中的以下行抛出异常并将我的来宾(未登录)用户重定向到登录页面:

before_filter :authenticate_user!, :except => [:show, :index]

我将其更改为:

before_filter :authenticate_user!, :except => [:show, :index, :random]

现在代码按预期工作:访客用户可以查看创建的新随机集,但不能“保存”它们,除非他们首先登录。

所以,我真正的问题在于 Devise(或者实际上是我的 Devise 配置),而不是 CanCan。

于 2010-05-14T15:06:35.323 回答
0

好吧,正确的做法是使用 CanCan 能力类来定义正确的授权规则。

在能力.rb

  def initialize(user)
#everyone
    can [:read, :random], [CardSet]
#everyone who is editor
    if user.editor?
      can [:new, :create], [CardSet]

ETC

问题是, :random 操作所做的第一件事是构建 CardSet 模型的新实例来填充视图。当 cancan 尝试 load_and_authorize_resource 一个新的 CardSet 时,它会抛出一个 CanCan::AccessDenied 异常。

虽然 CanCan 授权控制器动作,但在随机动作中构建新实例(即 CardSet.new)不在 CanCan 的范围内。您可能会收到错误,因为您没有在 Ability.rb 中定义随机操作的规则。我上面的例子应该可以解决你的问题

于 2010-05-14T09:32:43.720 回答