我正在编写一个网络应用程序,用于从较大的完整卡片组中随机选择卡片列表。我有一个卡片模型和一个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
答案 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中为随机操作定义任何规则。我上面的例子可以解决你的问题