diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb index f1a45d5..1d1df1c 100644 --- a/lib/cancan/ability.rb +++ b/lib/cancan/ability.rb @@ -117,7 +117,7 @@ module CanCan # can :read, :stats # can? :read, :stats # => true # - def can(action, subject, conditions = nil, &block) + def can(action = nil, subject = nil, conditions = nil, &block) can_definitions << CanDefinition.new(true, action, subject, conditions, block) end @@ -133,7 +133,7 @@ module CanCan # product.invisible? # end # - def cannot(action, subject, conditions = nil, &block) + def cannot(action = nil, subject = nil, conditions = nil, &block) can_definitions << CanDefinition.new(false, action, subject, conditions, block) end diff --git a/lib/cancan/can_definition.rb b/lib/cancan/can_definition.rb index e61dd94..dea8432 100644 --- a/lib/cancan/can_definition.rb +++ b/lib/cancan/can_definition.rb @@ -11,6 +11,7 @@ module CanCan # and subject respectively (such as :read, @project). The third argument is a hash # of conditions and the last one is the block passed to the "can" call. def initialize(base_behavior, action, subject, conditions, block) + @match_all = action.nil? && subject.nil? @base_behavior = base_behavior @actions = [action].flatten @subjects = [subject].flatten @@ -20,12 +21,14 @@ module CanCan # Matches both the subject and action, not necessarily the conditions def relevant?(action, subject) - matches_action?(action) && matches_subject?(subject) + @match_all || (matches_action?(action) && matches_subject?(subject)) end # Matches the block or conditions hash def matches_conditions?(action, subject, extra_args) - if @block && subject.class != Class + if @match_all + call_block_with_all(action, subject, extra_args) + elsif @block && subject.class != Class @block.call(subject, *extra_args) elsif @conditions.kind_of?(Hash) && subject.class != Class matches_conditions_hash?(subject) @@ -91,5 +94,13 @@ module CanCan end end end + + def call_block_with_all(action, subject, extra_args) + if subject.class == Class + @block.call(action, subject, nil, *extra_args) + else + @block.call(action, subject.class, subject, *extra_args) + end + end end end diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index e23c7a3..9be365a 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -79,8 +79,10 @@ describe CanCan::Ability do @ability.can?(:increment, 123).should be_true end - it "should return block result and only pass object for any action" do - @ability.can :manage, :all do |object| + it "should always call block with arguments when passing no arguments to can" do + @ability.can do |action, object_class, object| + action.should == :foo + object_class.should == 123.class object.should == 123 @block_called = true end @@ -88,6 +90,17 @@ describe CanCan::Ability do @block_called.should be_true end + it "should pass nil to object when comparing class with can check" do + @ability.can do |action, object_class, object| + action.should == :foo + object_class.should == Hash + object.should be_nil + @block_called = true + end + @ability.can?(:foo, Hash) + @block_called.should be_true + end + it "should automatically alias index and show into read calls" do @ability.can :read, :all @ability.can?(:index, 123).should be_true