cancan 1.6.4 → 1.6.5
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|