cancan 1.6.4 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +18 -0
- data/lib/cancan.rb +1 -1
- data/lib/cancan/controller_additions.rb +1 -1
- data/lib/cancan/controller_resource.rb +2 -2
- data/lib/cancan/model_adapters/active_record_adapter.rb +1 -1
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +11 -12
- data/lib/cancan/model_adapters/mongoid_adapter.rb +22 -9
- data/lib/cancan/rule.rb +1 -1
- data/spec/cancan/ability_spec.rb +7 -0
- data/spec/cancan/controller_additions_spec.rb +1 -1
- data/spec/cancan/controller_resource_spec.rb +4 -1
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +9 -0
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +0 -1
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +26 -0
- metadata +5 -5
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
1.6.5 (May 18, 2011)
|
2
|
+
|
3
|
+
* pass action and subject through AccessDenied exception when :through isn't found - issue #366
|
4
|
+
|
5
|
+
* many Mongoid adapter improvements (thanks rahearn, cardagin) - issues #363, #352, #343
|
6
|
+
|
7
|
+
* allow :through option to work with private controller methods - issue #360
|
8
|
+
|
9
|
+
* ensure Mongoid::Document is defined before loading Mongoid adapter - issue #359
|
10
|
+
|
11
|
+
* many DataMapper adapter improvements (thanks emmanuel) - issue #355
|
12
|
+
|
13
|
+
* handle checking nil attributes through associations (thanks thatothermitch) - issue #330
|
14
|
+
|
15
|
+
* improve scope merging - issue #328
|
16
|
+
|
17
|
+
|
18
|
+
|
1
19
|
1.6.4 (March 29, 2011)
|
2
20
|
|
3
21
|
* Fixed mongoid 'or' error - see issue #322
|
data/lib/cancan.rb
CHANGED
@@ -10,4 +10,4 @@ require 'cancan/model_adapters/abstract_adapter'
|
|
10
10
|
require 'cancan/model_adapters/default_adapter'
|
11
11
|
require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
|
12
12
|
require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
|
13
|
-
require 'cancan/model_adapters/mongoid_adapter' if defined? Mongoid
|
13
|
+
require 'cancan/model_adapters/mongoid_adapter' if defined?(Mongoid) && defined?(Mongoid::Document)
|
@@ -286,7 +286,7 @@ module CanCan
|
|
286
286
|
|
287
287
|
def self.included(base)
|
288
288
|
base.extend ClassMethods
|
289
|
-
base.helper_method :can?, :cannot
|
289
|
+
base.helper_method :can?, :cannot?, :current_ability
|
290
290
|
end
|
291
291
|
|
292
292
|
# Raises a CanCan::AccessDenied exception if the current_ability cannot
|
@@ -159,7 +159,7 @@ module CanCan
|
|
159
159
|
elsif @options[:shallow]
|
160
160
|
resource_class
|
161
161
|
else
|
162
|
-
raise AccessDenied # maybe this should be a record not found error instead?
|
162
|
+
raise AccessDenied.new(nil, authorization_action, resource_class) # maybe this should be a record not found error instead?
|
163
163
|
end
|
164
164
|
else
|
165
165
|
resource_class
|
@@ -178,7 +178,7 @@ module CanCan
|
|
178
178
|
def fetch_parent(name)
|
179
179
|
if @controller.instance_variable_defined? "@#{name}"
|
180
180
|
@controller.instance_variable_get("@#{name}")
|
181
|
-
elsif @controller.respond_to?
|
181
|
+
elsif @controller.respond_to?(name, true)
|
182
182
|
@controller.send(name)
|
183
183
|
end
|
184
184
|
end
|
@@ -10,23 +10,22 @@ module CanCan
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.matches_conditions_hash?(subject, conditions)
|
13
|
-
|
13
|
+
collection = DataMapper::Collection.new(subject.query, [ subject ])
|
14
|
+
!!collection.first(conditions)
|
14
15
|
end
|
15
16
|
|
16
17
|
def database_records
|
17
|
-
scope = @model_class.all(:conditions => ["0=1"])
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
scope = @model_class.all(:conditions => ["0 = 1"])
|
19
|
+
cans, cannots = @rules.partition { |r| r.base_behavior }
|
20
|
+
return scope if cans.empty?
|
21
|
+
# apply unions first, then differences. this mean cannot overrides can
|
22
|
+
cans.each { |r| scope += @model_class.all(:conditions => r.conditions) }
|
23
|
+
cannots.each { |r| scope -= @model_class.all(:conditions => r.conditions) }
|
21
24
|
scope
|
22
25
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
26
|
+
end # class DataMapper
|
27
|
+
end # module ModelAdapters
|
28
|
+
end # module CanCan
|
30
29
|
|
31
30
|
DataMapper::Model.class_eval do
|
32
31
|
include CanCan::ModelAdditions::ClassMethods
|
@@ -6,7 +6,14 @@ module CanCan
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.override_conditions_hash_matching?(subject, conditions)
|
9
|
-
conditions.any?
|
9
|
+
conditions.any? do |k,v|
|
10
|
+
key_is_not_symbol = lambda { !k.kind_of?(Symbol) }
|
11
|
+
subject_value_is_array = lambda do
|
12
|
+
subject.respond_to?(k) && subject.send(k).is_a?(Array)
|
13
|
+
end
|
14
|
+
|
15
|
+
key_is_not_symbol.call || subject_value_is_array.call
|
16
|
+
end
|
10
17
|
end
|
11
18
|
|
12
19
|
def self.matches_conditions_hash?(subject, conditions)
|
@@ -16,16 +23,22 @@ module CanCan
|
|
16
23
|
end
|
17
24
|
|
18
25
|
def database_records
|
19
|
-
if @rules.size == 0
|
26
|
+
if @rules.size == 0
|
20
27
|
@model_class.where(:_id => {'$exists' => false, '$type' => 7}) # return no records in Mongoid
|
28
|
+
elsif @rules.size == 1 && @rules[0].conditions.is_a?(Mongoid::Criteria)
|
29
|
+
@rules[0].conditions
|
21
30
|
else
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
31
|
+
# we only need to process can rules if
|
32
|
+
# there are no rules with empty conditions
|
33
|
+
rules = @rules.reject { |rule| rule.conditions.empty? }
|
34
|
+
process_can_rules = @rules.count == rules.count
|
35
|
+
rules.inject(@model_class.all) do |records, rule|
|
36
|
+
if process_can_rules && rule.base_behavior
|
37
|
+
records.or rule.conditions
|
38
|
+
elsif !rule.base_behavior
|
39
|
+
records.excludes rule.conditions
|
27
40
|
else
|
28
|
-
records
|
41
|
+
records
|
29
42
|
end
|
30
43
|
end
|
31
44
|
end
|
@@ -37,4 +50,4 @@ end
|
|
37
50
|
# simplest way to add `accessible_by` to all Mongoid Documents
|
38
51
|
module Mongoid::Document::ClassMethods
|
39
52
|
include CanCan::ModelAdditions::ClassMethods
|
40
|
-
end
|
53
|
+
end
|
data/lib/cancan/rule.rb
CHANGED
@@ -109,7 +109,7 @@ module CanCan
|
|
109
109
|
if attribute.kind_of? Array
|
110
110
|
attribute.any? { |element| matches_conditions_hash? element, value }
|
111
111
|
else
|
112
|
-
matches_conditions_hash?
|
112
|
+
!attribute.nil? && matches_conditions_hash?(attribute, value)
|
113
113
|
end
|
114
114
|
elsif value.kind_of?(Array) || value.kind_of?(Range)
|
115
115
|
value.include? attribute
|
data/spec/cancan/ability_spec.rb
CHANGED
@@ -249,6 +249,13 @@ describe CanCan::Ability do
|
|
249
249
|
@ability.can?(:read, 1..5).should be_true
|
250
250
|
@ability.can?(:read, 4..6).should be_false
|
251
251
|
end
|
252
|
+
|
253
|
+
it "should not match subjects return nil for methods that must match nested a nested conditions hash" do
|
254
|
+
mock(object_with_foo = Object.new).foo { :bar }
|
255
|
+
@ability.can :read, Array, :first => { :foo => :bar }
|
256
|
+
@ability.can?(:read, [object_with_foo]).should be_true
|
257
|
+
@ability.can?(:read, []).should be_false
|
258
|
+
end
|
252
259
|
|
253
260
|
it "should not stop at cannot definition when comparing class" do
|
254
261
|
@ability.can :read, Range
|
@@ -6,7 +6,7 @@ describe CanCan::ControllerAdditions do
|
|
6
6
|
@controller = @controller_class.new
|
7
7
|
stub(@controller).params { {} }
|
8
8
|
stub(@controller).current_user { :current_user }
|
9
|
-
mock(@controller_class).helper_method(:can?, :cannot
|
9
|
+
mock(@controller_class).helper_method(:can?, :cannot?, :current_ability)
|
10
10
|
@controller_class.send(:include, CanCan::ControllerAdditions)
|
11
11
|
end
|
12
12
|
|
@@ -235,7 +235,10 @@ describe CanCan::ControllerResource do
|
|
235
235
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
236
236
|
lambda {
|
237
237
|
resource.load_resource
|
238
|
-
}.should raise_error(CanCan::AccessDenied)
|
238
|
+
}.should raise_error(CanCan::AccessDenied) { |exception|
|
239
|
+
exception.action.should == :show
|
240
|
+
exception.subject.should == Project
|
241
|
+
}
|
239
242
|
@controller.instance_variable_get(:@project).should be_nil
|
240
243
|
end
|
241
244
|
|
@@ -125,6 +125,15 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
|
125
125
|
Article.accessible_by(@ability).should == [article1]
|
126
126
|
end
|
127
127
|
|
128
|
+
it "should fetch only associated records when using with a scope for conditions" do
|
129
|
+
@ability.can :read, Article, Article.where(:secret => true)
|
130
|
+
category1 = Category.create!(:visible => false)
|
131
|
+
category2 = Category.create!(:visible => true)
|
132
|
+
article1 = Article.create!(:secret => true, :category => category1)
|
133
|
+
article2 = Article.create!(:secret => true, :category => category2)
|
134
|
+
category1.articles.accessible_by(@ability).should == [article1]
|
135
|
+
end
|
136
|
+
|
128
137
|
it "should raise an exception when trying to merge scope with other conditions" do
|
129
138
|
@ability.can :read, Article, :published => true
|
130
139
|
@ability.can :read, Article, Article.where(:secret => true)
|
@@ -65,7 +65,6 @@ if ENV["MODEL_ADAPTER"] == "data_mapper"
|
|
65
65
|
end
|
66
66
|
|
67
67
|
it "should fetch only the articles that are published and not secret" do
|
68
|
-
pending "the `cannot` may require some custom SQL, maybe abstract out from Active Record adapter"
|
69
68
|
@ability.can :read, Article, :published => true
|
70
69
|
@ability.cannot :read, Article, :secret => true
|
71
70
|
article1 = Article.create(:published => true, :secret => false)
|
@@ -42,6 +42,15 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
|
42
42
|
@ability.should be_able_to(:read, model)
|
43
43
|
end
|
44
44
|
|
45
|
+
it "should be able to read hashes when field is array" do
|
46
|
+
one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three'])
|
47
|
+
two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five'])
|
48
|
+
|
49
|
+
@ability.can :foo, MongoidProject, :numbers => 'one'
|
50
|
+
@ability.should be_able_to(:foo, one_to_three)
|
51
|
+
@ability.should_not be_able_to(:foo, two_to_five)
|
52
|
+
end
|
53
|
+
|
45
54
|
it "should return [] when no ability is defined so no records are found" do
|
46
55
|
MongoidProject.create(:title => 'Sir')
|
47
56
|
MongoidProject.create(:title => 'Lord')
|
@@ -59,6 +68,15 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
|
59
68
|
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
|
60
69
|
end
|
61
70
|
|
71
|
+
it "should be able to mix empty conditions and hashes" do
|
72
|
+
@ability.can :read, MongoidProject
|
73
|
+
@ability.can :read, MongoidProject, :title => 'Sir'
|
74
|
+
sir = MongoidProject.create(:title => 'Sir')
|
75
|
+
lord = MongoidProject.create(:title => 'Lord')
|
76
|
+
|
77
|
+
MongoidProject.accessible_by(@ability, :read).count.should == 2
|
78
|
+
end
|
79
|
+
|
62
80
|
it "should return everything when the defined ability is manage all" do
|
63
81
|
@ability.can :manage, :all
|
64
82
|
sir = MongoidProject.create(:title => 'Sir')
|
@@ -68,6 +86,14 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
|
68
86
|
MongoidProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
|
69
87
|
end
|
70
88
|
|
89
|
+
it "should allow a scope for conditions" do
|
90
|
+
@ability.can :read, MongoidProject, MongoidProject.where(:title => 'Sir')
|
91
|
+
sir = MongoidProject.create(:title => 'Sir')
|
92
|
+
lord = MongoidProject.create(:title => 'Lord')
|
93
|
+
dude = MongoidProject.create(:title => 'Dude')
|
94
|
+
|
95
|
+
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
|
96
|
+
end
|
71
97
|
|
72
98
|
describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
|
73
99
|
it "should handle :field.in" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cancan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 1.6.
|
9
|
+
- 5
|
10
|
+
version: 1.6.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Bates
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-05-18 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -161,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
161
|
requirements: []
|
162
162
|
|
163
163
|
rubyforge_project: cancan
|
164
|
-
rubygems_version: 1.
|
164
|
+
rubygems_version: 1.5.3
|
165
165
|
signing_key:
|
166
166
|
specification_version: 3
|
167
167
|
summary: Simple authorization solution for Rails.
|