我(最后)将CanCan / Ability连接到我的应用程序,我开始编写RSpec测试。但他们失败了 - 我的能力似乎过于宽容,我不明白为什么。
首先是Ability类。目的是非管理员用户只能自己管理。特别是,他们无法看到其他用户:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # create guest user if needed
if (user.has_role?(:admin))
can(:manage, :all)
else
can(:manage, User, :id => user.id)
end
end
end
RSpec测试:
require 'spec_helper'
require 'cancan/matchers'
describe Ability do
before(:each) do
@user = User.create
end
describe 'guest user' do
before(:each) do
@guest = nil
@ability = Ability.new(@guest)
end
it "should_not list other users" do
@ability.should_not be_able_to(:read, User)
end
it "should_not show other user" do
@ability.should_not be_able_to(:read, @user)
end
it "should_not create other user" do
@ability.should_not be_able_to(:create, User)
end
it "should_not update other user" do
@ability.should_not be_able_to(:update, @user)
end
it "should_not destroy other user" do
@ability.should_not be_able_to(:destroy, @user)
end
end
end
所有这五项测试都失败了。我已经阅读了Ryan's documentation的部分,他说:
重要:如果是块或哈希 条件存在他们将被忽略 在检查课程时,它会 返回true。
......但最多只能解释五次失败中的两次。很明显,我错过了一些基本的东西。
答案 0 :(得分:1)
我希望这可行:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # create guest user if needed
if (user.has_role?(:admin))
can(:manage, :all)
elsif user.persisted?
can(:manage, User, :id => user.id)
end
end
end
我不确定如果你传递:id => nil
的行为是什么,这是客户案例中发生的事情,但无论如何,如果你不希望访客访问列表查看,您根本不应该为该用户致电can :manage, User
。
一般来说,我发现分配user ||= User.new
会使这种能力更难以推理。
答案 1 :(得分:0)
require 'spec_helper'
require 'cancan/matchers'
describe Ability do
before(:each) { @user = User.create }
describe 'guest user' do
before(:each) { @ability = Ability.new(nil) }
subject { @ability } # take advantage of subject
it "should not be an admin user" do
@user.should_not be_admin
@user.should be_guest
end
it "should_not show other user" do
should_not be_able_to(:read, @user)
end
it "should_not create other user" do
should_not be_able_to(:create, User)
end
it "should_not update other user" do
should_not be_able_to(:update, @user)
end
it "should_not destroy other user" do
should_not be_able_to(:destroy, @user)
end
end
end
请注意,我也删除了此示例@ability.should_not be_able_to(:read, User)
。
希望它对你有所帮助。
答案 2 :(得分:0)
我有回答自己问题的坏习惯,但我给@jpemberthy和@Austin Taylor提供道具,指出我正确的方向。首先(这是化妆品),我将其添加到我的用户模型中:
class User
...
def self.create_guest
self.new
end
def guest?
uninitialized?
end
end
并相应地清理了我的能力模型:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.create_guest
if (user.admin?)
<admin abilities here>
elsif (user.guest?)
<guest abilities here>
else
<regular user abilities here>
end
end
end
但真正的解决方法是在我的RSpec测试中。由于用户对电子邮件和密码字段进行了验证,因此我的原始代码为:
before(:each) do
@user = User.create
end
失败了,因此创建了一个未初始化的@user
。由于:id字段为nil,因此Ability子句:
can(:manage, User, :id => user.id)
与访客用户一起成功,因为nil == nil(如果这是有道理的)。添加必要的字段以满足用户验证(几乎)一切正常。
道德:就像@jpemberthy在他的代码中建议的那样,总是包含一个测试,以确保您的用户对象具有他们应该拥有的权限! (我还有另外一个关于CanCan的问题,希望比这个更少的斩首,出现在你附近的StackOverflow话题中......)