25 Commits
1.6.2 ... 1.6.5

Author SHA1 Message Date
Ryan Bates
6a01427317 releasing 1.6.5 2011-05-18 13:24:14 -04:00
Ryan Bates
843fe89c63 pass action and subject through AccessDenied exception when :through isn't found - closes #366 2011-05-18 12:58:02 -04:00
Ryan Bates
74c9d582b2 Merge pull request #363 from rahearn/mongoid-conditions-empty
Fixes bug in mongoid_adapter with empty conditions hash
2011-05-17 10:22:19 -07:00
Ryan Bates
4e4c5a9a7f adding current_ability to helper methods - closes #361 2011-05-17 13:21:11 -04:00
Ryan Bates
dde88c92b7 allow :through option to work with private controller methods - closes #360 2011-05-17 13:18:31 -04:00
Ryan Bates
cb9777be5f ensure Mongoid::Document is defined before loading Mongoid adapter - closes #359 2011-05-17 13:16:33 -04:00
Ryan Ahearn
0882450232 Processes can rules only if no empty conditions rules are present
1) remove all empty conditions hashes from the rules, they are included
 in the records through `@model_class.all`
2) only process can rules if the new and old rules lists are the same
  length (meaning there were no empty conditions hashes)
3) always process cannot rules
2011-05-12 09:24:38 -04:00
Ryan Ahearn
ad62d60b20 Fixes bug in mongoid_adapter with empty conditions hash
* adds mongoid query that matches every record when
rule.conditions.empty? is true
2011-05-10 11:52:29 -04:00
Ryan Bates
ff13a82dda Merge pull request #355 from emmanuel/issue/245.
DataMapper adapter improvements
2011-05-02 13:52:11 -07:00
Emmanuel Gomez
16bdb8d42e Return empty set early if no can rules are present.
Thanks dkubb!
2011-04-29 12:04:19 -07:00
Emmanuel Gomez
d6851debd4 Fix pending spec for DataMapper adapter. 2011-04-29 00:46:38 -07:00
Emmanuel Gomez
6d39b0ae07 Use dkubb's suggestion for evaluating conditions against a Resource. 2011-04-29 00:31:27 -07:00
Ryan Bates
a6af47d213 Merged pull request #352 from cardagin/topic/mongoid-adapter-enhancements.
Augments Mongoid adapter by handling case where attribute is an array
2011-04-27 09:40:28 -07:00
John Feminella
17c52a7983 Augments Mongoid adapter by handling case where attribute is an array 2011-04-27 09:54:37 -04:00
Ryan Bates
18c1007d3f Merged pull request #343 from rahearn/mongoid-scope.
Adds ability to use Scope query with Mongoid
2011-04-25 09:19:53 -07:00
Ryan Ahearn
2b6204117f Adds ability to use Scope query with Mongoid
Same limitations apply as with active record
* can not be OR'd with other rules for same ability/controller
2011-04-15 16:58:19 -04:00
Ryan Bates
b1424dfa49 Merge branch 'optional-associations' of https://github.com/socialcast/cancan into socialcast-optional-associations 2011-04-01 15:13:02 -07:00
Mitch Williams
6aaab9e440 Fixed bug where conditions on an optionally associated object would throw exceptions if the associated object was not present at the rule match time. 2011-04-01 13:20:25 -07:00
Florent Piteau
a10243a569 When using an existing scope, it should be merged properly to the class. May fix ryanb/cancan#328 :) 2011-04-01 21:25:19 +02:00
Florent Piteau
81f00f9024 Failling test for nested resources with a scope for conditions 2011-04-01 18:45:33 +02:00
Ryan Bates
7bcfd3d295 releasing 1.6.4 2011-03-29 17:51:15 -07:00
Ryan Bates
e96cf5bea4 fixing mongoid 'or' error - closes #322 2011-03-29 17:49:18 -07:00
Ryan Bates
fb8e9bde57 releasing 1.6.3 2011-03-25 14:28:26 -07:00
Ryan Bates
89e40987d8 make sure ActiveRecord::Relation is defined before checking conditions against it so Rails 2 is supported again - closes #312 2011-03-25 14:26:33 -07:00
Ryan Bates
1ac8099f7a return subject passed to authorize! - closes #314 2011-03-25 14:24:43 -07:00
16 changed files with 123 additions and 32 deletions

View File

@@ -1,3 +1,33 @@
1.6.5 (May 18, 2011)
* pass action and subject through AccessDenied exception when :through isn't found - issue #366
* many Mongoid adapter improvements (thanks rahearn, cardagin) - issues #363, #352, #343
* allow :through option to work with private controller methods - issue #360
* ensure Mongoid::Document is defined before loading Mongoid adapter - issue #359
* many DataMapper adapter improvements (thanks emmanuel) - issue #355
* handle checking nil attributes through associations (thanks thatothermitch) - issue #330
* improve scope merging - issue #328
1.6.4 (March 29, 2011)
* Fixed mongoid 'or' error - see issue #322
1.6.3 (March 25, 2011)
* Make sure ActiveRecord::Relation is defined before checking conditions against it so Rails 2 is supported again - see issue #312
* Return subject passed to authorize! - see issue #314
1.6.2 (March 18, 2011)
* Fixed instance loading when :singleton option is used - see issue #310

View File

@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "cancan"
s.version = "1.6.2"
s.version = "1.6.5"
s.author = "Ryan Bates"
s.email = "ryan@railscasts.com"
s.homepage = "http://github.com/ryanb/cancan"

View File

@@ -10,4 +10,4 @@ require 'cancan/model_adapters/abstract_adapter'
require 'cancan/model_adapters/default_adapter'
require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
require 'cancan/model_adapters/mongoid_adapter' if defined? Mongoid
require 'cancan/model_adapters/mongoid_adapter' if defined?(Mongoid) && defined?(Mongoid::Document)

View File

@@ -201,6 +201,7 @@ module CanCan
message ||= unauthorized_message(action, subject)
raise AccessDenied.new(message, action, subject)
end
subject
end
def unauthorized_message(action, subject)

View File

@@ -286,7 +286,7 @@ module CanCan
def self.included(base)
base.extend ClassMethods
base.helper_method :can?, :cannot?
base.helper_method :can?, :cannot?, :current_ability
end
# Raises a CanCan::AccessDenied exception if the current_ability cannot

View File

@@ -159,7 +159,7 @@ module CanCan
elsif @options[:shallow]
resource_class
else
raise AccessDenied # maybe this should be a record not found error instead?
raise AccessDenied.new(nil, authorization_action, resource_class) # maybe this should be a record not found error instead?
end
else
resource_class
@@ -178,7 +178,7 @@ module CanCan
def fetch_parent(name)
if @controller.instance_variable_defined? "@#{name}"
@controller.instance_variable_get("@#{name}")
elsif @controller.respond_to? name
elsif @controller.respond_to?(name, true)
@controller.send(name)
end
end

View File

@@ -87,7 +87,7 @@ module CanCan
def database_records
if override_scope
override_scope
@model_class.scoped.merge(override_scope)
elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
@model_class.where(conditions).joins(joins)
else
@@ -99,7 +99,7 @@ module CanCan
def override_scope
conditions = @rules.map(&:conditions).compact
if conditions.any? { |c| c.kind_of?(ActiveRecord::Relation) }
if defined?(ActiveRecord::Relation) && conditions.any? { |c| c.kind_of?(ActiveRecord::Relation) }
if conditions.size == 1
conditions.first
else

View File

@@ -10,23 +10,22 @@ module CanCan
end
def self.matches_conditions_hash?(subject, conditions)
subject.class.all(:conditions => conditions).include?(subject) # TODO don't use a database query here for performance and other instances
collection = DataMapper::Collection.new(subject.query, [ subject ])
!!collection.first(conditions)
end
def database_records
scope = @model_class.all(:conditions => ["0 = 1"])
conditions.each do |condition|
scope += @model_class.all(:conditions => condition)
end
cans, cannots = @rules.partition { |r| r.base_behavior }
return scope if cans.empty?
# apply unions first, then differences. this mean cannot overrides can
cans.each { |r| scope += @model_class.all(:conditions => r.conditions) }
cannots.each { |r| scope -= @model_class.all(:conditions => r.conditions) }
scope
end
def conditions
@rules.map(&:conditions)
end
end
end
end
end # class DataMapper
end # module ModelAdapters
end # module CanCan
DataMapper::Model.class_eval do
include CanCan::ModelAdditions::ClassMethods

View File

@@ -6,7 +6,14 @@ module CanCan
end
def self.override_conditions_hash_matching?(subject, conditions)
conditions.any? { |k,v| !k.kind_of?(Symbol) }
conditions.any? do |k,v|
key_is_not_symbol = lambda { !k.kind_of?(Symbol) }
subject_value_is_array = lambda do
subject.respond_to?(k) && subject.send(k).is_a?(Array)
end
key_is_not_symbol.call || subject_value_is_array.call
end
end
def self.matches_conditions_hash?(subject, conditions)
@@ -18,12 +25,20 @@ module CanCan
def database_records
if @rules.size == 0
@model_class.where(:_id => {'$exists' => false, '$type' => 7}) # return no records in Mongoid
elsif @rules.size == 1 && @rules[0].conditions.is_a?(Mongoid::Criteria)
@rules[0].conditions
else
@rules.inject(@model_class.all) do |records, rule|
if rule.base_behavior
records.or(rule.conditions)
# we only need to process can rules if
# there are no rules with empty conditions
rules = @rules.reject { |rule| rule.conditions.empty? }
process_can_rules = @rules.count == rules.count
rules.inject(@model_class.all) do |records, rule|
if process_can_rules && rule.base_behavior
records.or rule.conditions
elsif !rule.base_behavior
records.excludes rule.conditions
else
records.excludes(rule.conditions)
records
end
end
end

View File

@@ -109,7 +109,7 @@ module CanCan
if attribute.kind_of? Array
attribute.any? { |element| matches_conditions_hash? element, value }
else
matches_conditions_hash? attribute, value
!attribute.nil? && matches_conditions_hash?(attribute, value)
end
elsif value.kind_of?(Array) || value.kind_of?(Range)
value.include? attribute

View File

@@ -250,6 +250,13 @@ describe CanCan::Ability do
@ability.can?(:read, 4..6).should be_false
end
it "should not match subjects return nil for methods that must match nested a nested conditions hash" do
mock(object_with_foo = Object.new).foo { :bar }
@ability.can :read, Array, :first => { :foo => :bar }
@ability.can?(:read, [object_with_foo]).should be_true
@ability.can?(:read, []).should be_false
end
it "should not stop at cannot definition when comparing class" do
@ability.can :read, Range
@ability.cannot :read, Range, :begin => 1
@@ -317,9 +324,11 @@ describe CanCan::Ability do
end
end
it "should not raise access denied exception if ability is authorized to perform an action" do
it "should not raise access denied exception if ability is authorized to perform an action and return subject" do
@ability.can :read, :foo
lambda { @ability.authorize!(:read, :foo) }.should_not raise_error
lambda {
@ability.authorize!(:read, :foo).should == :foo
}.should_not raise_error
end
it "should know when block is used in conditions" do

View File

@@ -6,7 +6,7 @@ describe CanCan::ControllerAdditions do
@controller = @controller_class.new
stub(@controller).params { {} }
stub(@controller).current_user { :current_user }
mock(@controller_class).helper_method(:can?, :cannot?)
mock(@controller_class).helper_method(:can?, :cannot?, :current_ability)
@controller_class.send(:include, CanCan::ControllerAdditions)
end

View File

@@ -235,7 +235,10 @@ describe CanCan::ControllerResource do
resource = CanCan::ControllerResource.new(@controller, :through => :category)
lambda {
resource.load_resource
}.should raise_error(CanCan::AccessDenied)
}.should raise_error(CanCan::AccessDenied) { |exception|
exception.action.should == :show
exception.subject.should == Project
}
@controller.instance_variable_get(:@project).should be_nil
end

View File

@@ -125,6 +125,15 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
Article.accessible_by(@ability).should == [article1]
end
it "should fetch only associated records when using with a scope for conditions" do
@ability.can :read, Article, Article.where(:secret => true)
category1 = Category.create!(:visible => false)
category2 = Category.create!(:visible => true)
article1 = Article.create!(:secret => true, :category => category1)
article2 = Article.create!(:secret => true, :category => category2)
category1.articles.accessible_by(@ability).should == [article1]
end
it "should raise an exception when trying to merge scope with other conditions" do
@ability.can :read, Article, :published => true
@ability.can :read, Article, Article.where(:secret => true)

View File

@@ -65,7 +65,6 @@ if ENV["MODEL_ADAPTER"] == "data_mapper"
end
it "should fetch only the articles that are published and not secret" do
pending "the `cannot` may require some custom SQL, maybe abstract out from Active Record adapter"
@ability.can :read, Article, :published => true
@ability.cannot :read, Article, :secret => true
article1 = Article.create(:published => true, :secret => false)

View File

@@ -42,6 +42,15 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
@ability.should be_able_to(:read, model)
end
it "should be able to read hashes when field is array" do
one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three'])
two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five'])
@ability.can :foo, MongoidProject, :numbers => 'one'
@ability.should be_able_to(:foo, one_to_three)
@ability.should_not be_able_to(:foo, two_to_five)
end
it "should return [] when no ability is defined so no records are found" do
MongoidProject.create(:title => 'Sir')
MongoidProject.create(:title => 'Lord')
@@ -59,6 +68,15 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
end
it "should be able to mix empty conditions and hashes" do
@ability.can :read, MongoidProject
@ability.can :read, MongoidProject, :title => 'Sir'
sir = MongoidProject.create(:title => 'Sir')
lord = MongoidProject.create(:title => 'Lord')
MongoidProject.accessible_by(@ability, :read).count.should == 2
end
it "should return everything when the defined ability is manage all" do
@ability.can :manage, :all
sir = MongoidProject.create(:title => 'Sir')
@@ -68,6 +86,14 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
MongoidProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
end
it "should allow a scope for conditions" do
@ability.can :read, MongoidProject, MongoidProject.where(:title => 'Sir')
sir = MongoidProject.create(:title => 'Sir')
lord = MongoidProject.create(:title => 'Lord')
dude = MongoidProject.create(:title => 'Dude')
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
end
describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
it "should handle :field.in" do