我是否应该通过CanCan跳过实例化资源的操作的授权?

时间:2010-05-14 03:45:32

标签: ruby-on-rails cancan

我正在编写一个网络应用程序,用于从较大的完整卡片组中随机选择卡片列表。我有一个卡片模型和一个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

我添加了Devise用于身份验证,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吗?我应该继续添加例外吗?

更新

我没有在上面包含我的Ability类。我已将其更新为包含':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

2 个答案:

答案 0 :(得分:3)

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

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

我把它改为:

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

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

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

答案 1 :(得分:0)

嗯,正确的做法是使用CanCan能力等级来定义正确的授权规则。

in Ability.rb

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

  

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

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