为什么我的 CanCan 能力课程过于宽松?
我(最后)将 CanCan/Ability 连接到我的应用程序中,并开始编写 RSpec 测试。但他们失败了——我的能力似乎过于宽容,我不明白为什么。
首先是能力类。目的是非管理员用户只能管理自己。特别是,他们无法查看其他用户:
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 的文档的部分,他说:
重要提示:如果一个块或散列 条件存在将被忽略 当检查一个类时,它会 返回真。
……但这最多只能解释五次失败中的两次。很明显我错过了一些基本的东西。
I'm (finally) wiring CanCan / Ability into my app, and I've started by writing the RSpec tests. But they're failing — my Abilities appear to be overly permissive, and I don't understand why.
First, the Ability class. The intention is that non-admin users can manage only themselves. In particular, they cannot look at other users:
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
The RSpec tests:
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
All five of these tests fail. I've read the part of Ryan's documentation where he says:
Important: If a block or hash of
conditions exist they will be ignored
when checking on a class, and it will
return true.
... but at most, that would only explain two of the five failures. So clearly I'm missing something fundamental.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我希望这能起作用:
我不确定如果您传递
:id =>; 则行为被定义为什么。 nil
,这是在访客情况下发生的情况,但无论如何,如果您不希望访客访问列表视图,则不应调用can :manage, User
对于该用户来说。一般来说,我发现分配
user ||= User.new
会使该功能更难以推理。I would expect this to work:
I'm not sure what the behavior is defined to be if you pass
:id => nil
, which is what happens in the guest case, but at any rate, if you don't want the guest to access the list view, you shouldn't callcan :manage, User
for that user at all.In general, I find that assigning
user ||= User.new
to make the ability harder to reason about.嘿,显然这应该可行,但是一些重构可以帮助您找到问题:
请注意,我还删除了这个示例
@ability.should_not be_able_to(:read, User)
。希望对您有帮助。
Hey, apparently this should work, but some refactoring would help you to find the issue:
Note that also I removed this example
@ability.should_not be_able_to(:read, User)
.Hope it helps you.
我有自己回答问题的坏习惯,但我感谢@jpemberthy 和@Austin Taylor 为我指明了正确的方向。首先(这是装饰性的),我将其添加到我的用户模型中:
并相应地清理了我的能力模型:
但真正的修复是在我的 RSpec 测试中。由于用户对电子邮件和密码字段进行了验证,因此我的原始代码:
失败,从而创建了一个未初始化的
@user
。由于 :id 字段为 nil,Ability 子句:对于来宾用户来说是成功的,因为 nil == nil (如果这有意义的话)。添加必填字段以满足用户验证使得(几乎)一切正常。
道德:正如 @jpemberthy 在他的代码中建议的那样,始终包含一个测试以确保您的用户对象拥有它们应有的权限! (我还有另一个关于 CanCan 的问题,希望没有这个问题那么愚蠢,出现在你附近的 StackOverflow 主题中......)
I've got this bad habit of answering my own questions, but I give props to @jpemberthy and @Austin Taylor for pointing me in the right direction. First (and this is cosmetic), I added this to my User model:
and cleaned up my Abilities model accordingly:
But the real fix was in my RSpec tests. Since User has validations on email and password fields, my original code of:
was failing, thus creating an uninitialized
@user
. Since the :id field was nil, the Ability clause:was succeeding with a guest user because nil == nil (if that makes sense). Adding the required fields to satisfy the User validations made (almost) everything work.
Moral: just as @jpemberthy suggested in his code, always include a test to make sure your user objects have the privileges that they are supposed to! (I still have another question regarding CanCan, hopefully less boneheaded than this one, appearing in a StackOverflow topic near you...)