почему мой класс CanCan Ability чрезмерно разрешающий? - PullRequest
2 голосов
/ 24 мая 2011

Я (наконец) подключил 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

Все пять из этих тестов не пройдены.Я прочитал часть документации Райана , где он говорит:

Важно: если существует блок или хэш условий, они будут игнорироваться при проверке класса, ивернет true.

... но самое большее, это объяснило бы только два из пяти сбоев.Ясно, что я упускаю что-то фундаментальное.

Ответы [ 3 ]

1 голос
/ 25 мая 2011

Я ожидал бы, что это сработает:

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 дает возможностьТруднее рассуждать.

0 голосов
/ 25 мая 2011

У меня есть плохая привычка отвечать на мои собственные вопросы, но я даю реквизиты @jpemberthy и @Austin Taylor за то, что они указали мне правильное направление. Сначала (и это косметика) я добавил это в свою модель User:

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 было ноль, предложение Ability:

can(:manage, User, :id => user.id)

успешно с гостевым пользователем, потому что nil == nil (если это имеет смысл). Добавление обязательных полей для удовлетворения пользовательских проверок сделало (почти) все работает.

Мораль: так же, как @jpemberthy предлагает в своем коде, всегда включайте тест, чтобы убедиться, что ваши пользовательские объекты имеют привилегии, которые они должны! (У меня все еще есть другой вопрос, касающийся CanCan, который, как мы надеемся, менее умен, чем этот, который появляется в ближайшей к вам теме StackOverflow ...)

0 голосов
/ 24 мая 2011

Эй, очевидно, это должно сработать, но некоторый рефакторинг поможет вам найти проблему:

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).

Надеюсь, это поможетвы.

...