【问题标题】:CanCan seems to ignore blockCanCan 似乎忽略了块
【发布时间】:2023-07-01 00:54:01
【问题描述】:

我正在使用 cancan gem,但遇到了一些问题。我写了一些简单的测试,但对于没有分配角色的用户来说失败了。可以看出,在Ability 类中,我试图说一个用户只有拥有:admin 角色才能管理其他用户。正如评论所指出的,该块永远不会被调用。

当你将一个块传递给can时,在cancan gem中?方法它将它添加到规则中,然后在您调用 can?方法,除非传入的对象的类是Class。因此,当我执行下面的测试时,它失败了,因为我传递了一个用户和 User.class== 类。

it { should_not be_able_to(:create, User) }
or
it "cannot create a User" do
  expect(ability.cannot? :create, User).to be_true
end

考虑到这一点,如果我编写一个测试特定用户的测试,则测试通过:

it { should_not be_able_to(:edit, FactoryGirl.create(:user) ) }   # passes, but...

但是,当您列出或创建时,这是没有意义的:

it { should_not be_able_to(:create, FactoryGirl.create(:user) ) }  # yuck

我猜你可以使用

it { should_not be_able_to(:create, User.new ) }  # but that is still full of suck

参考代码:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new

    can :manage, User do |u|
      # this block never gets called
      user.has_role? :admin
    end
  end
end


describe "user without roles" do
  subject { ability }
  let(:ability) { Ability.new create(:user) }

  it { should_not be_able_to(:manage, User) }  # passes
  it { should_not be_able_to(:index, User) }   # all the rest fail
  it { should_not be_able_to(:new, User) }
  it { should_not be_able_to(:edit, User) }
  it { should_not be_able_to(:create, User) }
  it { should_not be_able_to(:update, User) }

end

# CANCAN CODE
# https://github.com/ryanb/cancan/blob/c88cb8f4593148f99e15627d23fbf67116dd8be2/lib/cancan/can_definition.rb#L32
def matches_conditions?(action, subject, extra_args)
  if @match_all
    call_block_with_all(action, subject, extra_args)

  ## The condition in question, this is where I should go to
  ## subject -> User
  ## User.class -> Class
  elsif @block && !subject_class?(subject)
    @block.call(subject, *extra_args)
  elsif @conditions.kind_of?(Hash) && subject.kind_of?(Hash)
    nested_subject_matches_conditions?(subject)
  elsif @conditions.kind_of?(Hash) && !subject_class?(subject)
    matches_conditions_hash?(subject)
  else
    @base_behavior
  end
end

# User class returns true
def subject_class?(subject)
  (subject.kind_of?(Hash) ? subject.values.first : subject).class == Class
end

由于康康舞很受欢迎,我把钱放在了我做错事的事实上。任何帮助将不胜感激。

【问题讨论】:

    标签: ruby-on-rails cancan


    【解决方案1】:

    看起来下面的代码是我在能力类中应该有的:

    can :manage, User if user.has_role? :admin 
    

    【讨论】:

      【解决方案2】:

      你不使用 |u|在你的街区:

      can :manage, User do |u|
        u.has_role? :admin
      end
      

      尝试使用https://gist.github.com/fotinakis/3a532a0929f64b4b5352 进行测试。它们将如下所示:

      context "user without roles" do
        it "can view everything" do
          expect(@guest).to have_ability(:read, for: "all")
        end
      
        it "cannot edit or delete anything" do
          expect(@guest).to_not have_ability(:manage, for: "all")
        end
      end
      

      【讨论】: