diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 3e04fdc..62d219c 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,5 +1,7 @@ 1.1.0 (not released) +* Supporting arrays, ranges, and nested hashes in ability conditions + * Removing "unauthorized!" method in favor of "authorize!" in controllers * Adding action, subject and default_message abilities to AccessDenied exception - see issue #40 diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb index 9bd268b..75c7826 100644 --- a/lib/cancan/ability.rb +++ b/lib/cancan/ability.rb @@ -244,15 +244,26 @@ module CanCan if subject.class == Class true else - defined_conditions.all? do |name, value| - subject.send(name) == value - end + matches_conditions? subject, defined_conditions end else true end end + def matches_conditions?(subject, defined_conditions) + defined_conditions.all? do |name, value| + attribute = subject.send(name) + if value.kind_of?(Hash) + matches_conditions? attribute, value + elsif value.kind_of?(Array) || value.kind_of?(Range) + value.include? attribute + else + attribute == value + end + end + end + def includes_action?(actions, action) actions.include?(:manage) || actions.include?(action) end diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index c2df887..c51b22b 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -148,6 +148,26 @@ describe CanCan::Ability do @ability.can?(:read, Array).should be_true end + it "should allow an array of options in conditions hash" do + @ability.can :read, Array, :first => [1, 3, 5] + @ability.can?(:read, [1, 2, 3]).should be_true + @ability.can?(:read, [2, 3]).should be_false + @ability.can?(:read, [3, 4]).should be_true + end + + it "should allow a range of options in conditions hash" do + @ability.can :read, Array, :first => 1..3 + @ability.can?(:read, [1, 2, 3]).should be_true + @ability.can?(:read, [3, 4]).should be_true + @ability.can?(:read, [4, 5]).should be_false + end + + it "should allow nested hashes in conditions hash" do + @ability.can :read, Array, :first => { :length => 5 } + @ability.can?(:read, ["foo", "bar"]).should be_false + @ability.can?(:read, ["test1", "foo"]).should be_true + end + it "should return conditions for a given ability" do @ability.can :read, Array, :first => 1, :last => 3 @ability.conditions(:show, Array).should == {:first => 1, :last => 3}