Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: ryanb/cancan
base: 1.6.4
...
head fork: ryanb/cancan
compare: 1.6.5
  • 20 commits
  • 15 files changed
  • 0 commit comments
  • 6 contributors
Commits on Apr 01, 2011
@flop flop Failling test for nested resources with a scope for conditions 81f00f9
@flop flop When using an existing scope, it should be merged properly to the cla…
…ss. May fix ryanb/cancan#328 :)
a10243a
@thatothermitch thatothermitch Fixed bug where conditions on an optionally associated object would t…
…hrow exceptions if the associated object was not present at the rule match time.
6aaab9e
@ryanb Merge branch 'optional-associations' of https://github.com/socialcast…
…/cancan into socialcast-optional-associations
b1424df
Commits on Apr 15, 2011
@rahearn rahearn 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
2b62041
Commits on Apr 25, 2011
@ryanb Merged pull request #343 from rahearn/mongoid-scope.
Adds ability to use Scope query with Mongoid
18c1007
Commits on Apr 27, 2011
John Feminella Augments Mongoid adapter by handling case where attribute is an array 17c52a7
@ryanb Merged pull request #352 from cardagin/topic/mongoid-adapter-enhancem…
…ents.

Augments Mongoid adapter by handling case where attribute is an array
a6af47d
Commits on Apr 29, 2011
@emmanuel emmanuel Use dkubb's suggestion for evaluating conditions against a Resource. 6d39b0a
@emmanuel emmanuel Fix pending spec for DataMapper adapter. d6851de
@emmanuel emmanuel Return empty set early if no can rules are present.
Thanks dkubb!
16bdb8d
Commits on May 02, 2011
@ryanb Merge pull request #355 from emmanuel/issue/245.
DataMapper adapter improvements
ff13a82
Commits on May 10, 2011
@rahearn rahearn Fixes bug in mongoid_adapter with empty conditions hash
* adds mongoid query that matches every record when
rule.conditions.empty? is true
ad62d60
Commits on May 12, 2011
@rahearn rahearn 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
0882450
Commits on May 17, 2011
@ryanb ensure Mongoid::Document is defined before loading Mongoid adapter - …
…closes #359
cb9777b
@ryanb allow :through option to work with private controller methods - closes dde88c9
@ryanb adding current_ability to helper methods - closes #361 4e4c5a9
@ryanb Merge pull request #363 from rahearn/mongoid-conditions-empty
Fixes bug in mongoid_adapter with empty conditions hash
74c9d58
Commits on May 18, 2011
@ryanb pass action and subject through AccessDenied exception when :through …
…isn't found - closes #366
843fe89
@ryanb releasing 1.6.5 6a01427
View
18 CHANGELOG.rdoc
@@ -1,3 +1,21 @@
+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
View
2  cancan.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "cancan"
- s.version = "1.6.4"
+ s.version = "1.6.5"
s.author = "Ryan Bates"
s.email = "ryan@railscasts.com"
s.homepage = "http://github.com/ryanb/cancan"
View
2  lib/cancan.rb
@@ -10,4 +10,4 @@
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
2  lib/cancan/controller_additions.rb
@@ -286,7 +286,7 @@ def cancan_skipper
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
4 lib/cancan/controller_resource.rb
@@ -159,7 +159,7 @@ def resource_base
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 @@ def parent_resource
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
2  lib/cancan/model_adapters/active_record_adapter.rb
@@ -87,7 +87,7 @@ def joins
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
View
23 lib/cancan/model_adapters/data_mapper_adapter.rb
@@ -10,23 +10,22 @@ def self.override_conditions_hash_matching?(subject, conditions)
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
+ scope = @model_class.all(:conditions => ["0 = 1"])
+ 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
31 lib/cancan/model_adapters/mongoid_adapter.rb
@@ -6,7 +6,14 @@ def self.for_class?(model_class)
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)
@@ -16,16 +23,22 @@ def self.matches_conditions_hash?(subject, conditions)
end
def database_records
- if @rules.size == 0
+ 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.conditions.empty?
- records
- elsif 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
@@ -37,4 +50,4 @@ def database_records
# simplest way to add `accessible_by` to all Mongoid Documents
module Mongoid::Document::ClassMethods
include CanCan::ModelAdditions::ClassMethods
-end
+end
View
2  lib/cancan/rule.rb
@@ -109,7 +109,7 @@ def matches_conditions_hash?(subject, conditions = @conditions)
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
7 spec/cancan/ability_spec.rb
@@ -249,6 +249,13 @@
@ability.can?(:read, 1..5).should be_true
@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
View
2  spec/cancan/controller_additions_spec.rb
@@ -6,7 +6,7 @@
@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
5 spec/cancan/controller_resource_spec.rb
@@ -235,7 +235,10 @@
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
9 spec/cancan/model_adapters/active_record_adapter_spec.rb
@@ -125,6 +125,15 @@
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
1  spec/cancan/model_adapters/data_mapper_adapter_spec.rb
@@ -65,7 +65,6 @@ class Comment
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
26 spec/cancan/model_adapters/mongoid_adapter_spec.rb
@@ -42,6 +42,15 @@ class MongoidProject
@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 @@ class MongoidProject
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 @@ class MongoidProject
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

No commit comments for this range

Something went wrong with that request. Please try again.