cancan 1.2.0 → 1.3.2
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 +38 -0
- data/README.rdoc +14 -9
- data/Rakefile +12 -12
- data/lib/cancan.rb +1 -1
- data/lib/cancan/ability.rb +32 -35
- data/lib/cancan/active_record_additions.rb +3 -4
- data/lib/cancan/can_definition.rb +37 -47
- data/lib/cancan/controller_additions.rb +58 -26
- data/lib/cancan/controller_resource.rb +115 -40
- data/lib/cancan/query.rb +97 -0
- data/spec/cancan/ability_spec.rb +94 -43
- data/spec/cancan/active_record_additions_spec.rb +27 -4
- data/spec/cancan/can_definition_spec.rb +7 -7
- data/spec/cancan/controller_additions_spec.rb +12 -6
- data/spec/cancan/controller_resource_spec.rb +218 -26
- data/spec/cancan/query_spec.rb +107 -0
- data/spec/matchers.rb +13 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +25 -1
- metadata +10 -17
- data/lib/cancan/resource_authorization.rb +0 -70
- data/spec/cancan/resource_authorization_spec.rb +0 -135
@@ -2,16 +2,16 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe CanCan::ActiveRecordAdditions do
|
4
4
|
before(:each) do
|
5
|
-
@model_class = Class.new
|
5
|
+
@model_class = Class.new(Person)
|
6
6
|
stub(@model_class).scoped { :scoped_stub }
|
7
7
|
@model_class.send(:include, CanCan::ActiveRecordAdditions)
|
8
8
|
@ability = Object.new
|
9
9
|
@ability.extend(CanCan::Ability)
|
10
10
|
end
|
11
11
|
|
12
|
-
it "should call where(
|
13
|
-
stub(@model_class).where(
|
14
|
-
@model_class.accessible_by(@ability, :read).should == :
|
12
|
+
it "should call where('true=false') when no ability is defined so no records are found" do
|
13
|
+
stub(@model_class).where('true=false').stub!.joins(nil) { :no_match }
|
14
|
+
@model_class.accessible_by(@ability, :read).should == :no_match
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should call where with matching ability conditions" do
|
@@ -25,4 +25,27 @@ describe CanCan::ActiveRecordAdditions do
|
|
25
25
|
stub(@model_class).scoped(:conditions => {:foos => {:bar => 1}}, :joins => [:foo]) { :found_records }
|
26
26
|
@model_class.accessible_by(@ability).should == :found_records
|
27
27
|
end
|
28
|
+
|
29
|
+
it "should merge association joins and sanitize conditions" do
|
30
|
+
@ability.can :read, @model_class, :foo => {:bar => 1}
|
31
|
+
@ability.can :read, @model_class, :too => {:car => 1, :far => {:bar => 1}}
|
32
|
+
|
33
|
+
condition_variants = [
|
34
|
+
'(toos.far.bar=1 AND toos.car=1) OR (foos.bar=1)', # faked sql sanitizer is stupid ;-)
|
35
|
+
'(toos.car=1 AND toos.far.bar=1) OR (foos.bar=1)'
|
36
|
+
]
|
37
|
+
joins_variants = [
|
38
|
+
[:foo, {:too => [:far]}],
|
39
|
+
[{:too => [:far]}, :foo]
|
40
|
+
]
|
41
|
+
|
42
|
+
condition_variants.each do |condition|
|
43
|
+
joins_variants.each do |joins|
|
44
|
+
stub(@model_class).scoped( :conditions => condition, :joins => joins ) { :found_records }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# @ability.conditions(:read, @model_class).should == '(too.car=1 AND too.far.bar=1) OR (foo.bar=1)'
|
48
|
+
# @ability.associations_hash(:read, @model_class).should == [{:too => [:far]}, :foo]
|
49
|
+
@model_class.accessible_by(@ability).should == :found_records
|
50
|
+
end
|
28
51
|
end
|
@@ -7,38 +7,38 @@ describe CanCan::CanDefinition do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should return no association joins if none exist" do
|
10
|
-
@can.
|
10
|
+
@can.associations_hash.should == {}
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should return no association for joins if just attributes" do
|
14
14
|
@conditions[:foo] = :bar
|
15
|
-
@can.
|
15
|
+
@can.associations_hash.should == {}
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should return single association for joins" do
|
19
19
|
@conditions[:foo] = {:bar => 1}
|
20
|
-
@can.
|
20
|
+
@can.associations_hash.should == {:foo => {}}
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should return multiple associations for joins" do
|
24
24
|
@conditions[:foo] = {:bar => 1}
|
25
25
|
@conditions[:test] = {1 => 2}
|
26
|
-
@can.
|
26
|
+
@can.associations_hash.should == {:foo => {}, :test => {}}
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should return nested associations for joins" do
|
30
30
|
@conditions[:foo] = {:bar => {1 => 2}}
|
31
|
-
@can.
|
31
|
+
@can.associations_hash.should == {:foo => {:bar => {}}}
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should return table names in conditions for association joins" do
|
35
35
|
@conditions[:foo] = {:bar => 1}
|
36
36
|
@conditions[:test] = 1
|
37
|
-
@can.
|
37
|
+
@can.tableized_conditions.should == {:foos => {:bar => 1}, :test => 1}
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should return no association joins if conditions is nil" do
|
41
41
|
can = CanCan::CanDefinition.new(true, :read, Integer, nil, nil)
|
42
|
-
can.
|
42
|
+
can.associations_hash.should == {}
|
43
43
|
end
|
44
44
|
end
|
@@ -52,20 +52,26 @@ describe CanCan::ControllerAdditions do
|
|
52
52
|
@controller.cannot?(:foo, :bar).should be_true
|
53
53
|
end
|
54
54
|
|
55
|
-
it "load_and_authorize_resource should setup a before filter which passes call to
|
56
|
-
stub(CanCan::
|
55
|
+
it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do
|
56
|
+
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_and_authorize_resource
|
57
57
|
mock(@controller_class).before_filter({}) { |options, block| block.call(@controller) }
|
58
58
|
@controller_class.load_and_authorize_resource :foo => :bar
|
59
59
|
end
|
60
60
|
|
61
|
-
it "
|
62
|
-
stub(CanCan::
|
61
|
+
it "load_and_authorize_resource should properly pass first argument as the resource name" do
|
62
|
+
stub(CanCan::ControllerResource).new(@controller, :project, :foo => :bar).mock!.load_and_authorize_resource
|
63
|
+
mock(@controller_class).before_filter({}) { |options, block| block.call(@controller) }
|
64
|
+
@controller_class.load_and_authorize_resource :project, :foo => :bar
|
65
|
+
end
|
66
|
+
|
67
|
+
it "authorize_resource should setup a before filter which passes call to ControllerResource" do
|
68
|
+
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.authorize_resource
|
63
69
|
mock(@controller_class).before_filter(:except => :show) { |options, block| block.call(@controller) }
|
64
70
|
@controller_class.authorize_resource :foo => :bar, :except => :show
|
65
71
|
end
|
66
72
|
|
67
|
-
it "load_resource should setup a before filter which passes call to
|
68
|
-
stub(CanCan::
|
73
|
+
it "load_resource should setup a before filter which passes call to ControllerResource" do
|
74
|
+
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_resource
|
69
75
|
mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
|
70
76
|
@controller_class.load_resource :foo => :bar, :only => [:show, :index]
|
71
77
|
end
|
@@ -2,58 +2,250 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe CanCan::ControllerResource do
|
4
4
|
before(:each) do
|
5
|
-
@
|
5
|
+
@params = HashWithIndifferentAccess.new(:controller => "abilities")
|
6
|
+
@controller = Object.new # simple stub for now
|
7
|
+
stub(@controller).params { @params }
|
6
8
|
end
|
7
9
|
|
8
|
-
it "should
|
9
|
-
|
10
|
+
it "should load the resource into an instance variable if params[:id] is specified" do
|
11
|
+
@params.merge!(:action => "show", :id => 123)
|
12
|
+
stub(Ability).find(123) { :some_resource }
|
13
|
+
resource = CanCan::ControllerResource.new(@controller)
|
14
|
+
resource.load_resource
|
15
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
10
16
|
end
|
11
17
|
|
12
|
-
it "should
|
13
|
-
|
14
|
-
|
18
|
+
it "should not load resource into an instance variable if already set" do
|
19
|
+
@params.merge!(:action => "show", :id => 123)
|
20
|
+
@controller.instance_variable_set(:@ability, :some_ability)
|
21
|
+
resource = CanCan::ControllerResource.new(@controller)
|
22
|
+
resource.load_resource
|
15
23
|
@controller.instance_variable_get(:@ability).should == :some_ability
|
16
24
|
end
|
17
25
|
|
18
|
-
it "should
|
19
|
-
|
20
|
-
stub(
|
21
|
-
CanCan::ControllerResource.new(@controller
|
26
|
+
it "should properly load resource for namespaced controller" do
|
27
|
+
@params.merge!(:controller => "admin/abilities", :action => "show", :id => 123)
|
28
|
+
stub(Ability).find(123) { :some_resource }
|
29
|
+
resource = CanCan::ControllerResource.new(@controller)
|
30
|
+
resource.load_resource
|
31
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should properly load resource for namespaced controller when using '::' for namespace" do
|
35
|
+
@params.merge!(:controller => "Admin::AbilitiesController", :action => "show", :id => 123)
|
36
|
+
stub(Ability).find(123) { :some_resource }
|
37
|
+
resource = CanCan::ControllerResource.new(@controller)
|
38
|
+
resource.load_resource
|
39
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should build a new resource with hash if params[:id] is not specified" do
|
43
|
+
@params.merge!(:action => "create", :ability => {:foo => "bar"})
|
44
|
+
stub(Ability).new("foo" => "bar") { :some_resource }
|
45
|
+
resource = CanCan::ControllerResource.new(@controller)
|
46
|
+
resource.load_resource
|
47
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should build a new resource with no arguments if attribute hash isn't specified" do
|
51
|
+
@params[:action] = "new"
|
52
|
+
mock(Ability).new { :some_resource }
|
53
|
+
resource = CanCan::ControllerResource.new(@controller)
|
54
|
+
resource.load_resource
|
55
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not build a resource when on index action" do
|
59
|
+
@params[:action] = "index"
|
60
|
+
resource = CanCan::ControllerResource.new(@controller)
|
61
|
+
resource.load_resource
|
62
|
+
@controller.instance_variable_get(:@ability).should be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should perform authorization using controller action and loaded model" do
|
66
|
+
@params[:action] = "show"
|
67
|
+
@controller.instance_variable_set(:@ability, :some_resource)
|
68
|
+
stub(@controller).authorize!(:show, :some_resource) { raise CanCan::AccessDenied }
|
69
|
+
resource = CanCan::ControllerResource.new(@controller)
|
70
|
+
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should perform authorization using controller action and non loaded model" do
|
74
|
+
@params[:action] = "show"
|
75
|
+
stub(@controller).authorize!(:show, Ability) { raise CanCan::AccessDenied }
|
76
|
+
resource = CanCan::ControllerResource.new(@controller)
|
77
|
+
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should call load_resource and authorize_resource for load_and_authorize_resource" do
|
81
|
+
@params[:action] = "show"
|
82
|
+
resource = CanCan::ControllerResource.new(@controller)
|
83
|
+
mock(resource).load_resource
|
84
|
+
mock(resource).authorize_resource
|
85
|
+
resource.load_and_authorize_resource
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not build a resource when on custom collection action" do
|
89
|
+
@params[:action] = "sort"
|
90
|
+
resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
|
91
|
+
resource.load_resource
|
92
|
+
@controller.instance_variable_get(:@ability).should be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should build a resource when on custom new action even when params[:id] exists" do
|
96
|
+
@params.merge!(:action => "build", :id => 123)
|
97
|
+
stub(Ability).new { :some_resource }
|
98
|
+
resource = CanCan::ControllerResource.new(@controller, :new => :build)
|
99
|
+
resource.load_resource
|
100
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should not try to load resource for other action if params[:id] is undefined" do
|
104
|
+
@params[:action] = "list"
|
105
|
+
resource = CanCan::ControllerResource.new(@controller)
|
106
|
+
resource.load_resource
|
107
|
+
@controller.instance_variable_get(:@ability).should be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should be a parent resource when name is provided which doesn't match controller" do
|
111
|
+
resource = CanCan::ControllerResource.new(@controller, :person)
|
112
|
+
resource.should be_parent
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should not be a parent resource when name is provided which matches controller" do
|
116
|
+
resource = CanCan::ControllerResource.new(@controller, :ability)
|
117
|
+
resource.should_not be_parent
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should be parent if specified in options" do
|
121
|
+
resource = CanCan::ControllerResource.new(@controller, :ability, {:parent => true})
|
122
|
+
resource.should be_parent
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should not be parent if specified in options" do
|
126
|
+
resource = CanCan::ControllerResource.new(@controller, :person, {:parent => false})
|
127
|
+
resource.should_not be_parent
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should load parent resource through proper id parameter when supplying a resource with a different name" do
|
131
|
+
@params.merge!(:action => "index", :person_id => 123)
|
132
|
+
stub(Person).find(123) { :some_person }
|
133
|
+
resource = CanCan::ControllerResource.new(@controller, :person)
|
134
|
+
resource.load_resource
|
135
|
+
@controller.instance_variable_get(:@person).should == :some_person
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should load parent resource for collection action" do
|
139
|
+
@params.merge!(:action => "index", :person_id => 456)
|
140
|
+
stub(Person).find(456) { :some_person }
|
141
|
+
resource = CanCan::ControllerResource.new(@controller, :person)
|
142
|
+
resource.load_resource
|
143
|
+
@controller.instance_variable_get(:@person).should == :some_person
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should load resource through the association of another parent resource" do
|
147
|
+
@params.merge!(:action => "show", :id => 123)
|
148
|
+
person = Object.new
|
149
|
+
@controller.instance_variable_set(:@person, person)
|
150
|
+
stub(person).abilities.stub!.find(123) { :some_ability }
|
151
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :person)
|
152
|
+
resource.load_resource
|
22
153
|
@controller.instance_variable_get(:@ability).should == :some_ability
|
23
154
|
end
|
24
155
|
|
25
|
-
it "should
|
26
|
-
|
27
|
-
|
156
|
+
it "should not load through parent resource if instance isn't loaded" do
|
157
|
+
@params.merge!(:action => "show", :id => 123)
|
158
|
+
stub(Ability).find(123) { :some_ability }
|
159
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :person)
|
160
|
+
resource.load_resource
|
28
161
|
@controller.instance_variable_get(:@ability).should == :some_ability
|
29
162
|
end
|
30
163
|
|
31
|
-
it "should
|
32
|
-
|
33
|
-
|
34
|
-
|
164
|
+
it "should load through first matching if multiple are given" do
|
165
|
+
@params.merge!(:action => "show", :id => 123)
|
166
|
+
person = Object.new
|
167
|
+
@controller.instance_variable_set(:@person, person)
|
168
|
+
stub(person).abilities.stub!.find(123) { :some_ability }
|
169
|
+
resource = CanCan::ControllerResource.new(@controller, :through => [:thing, :person])
|
170
|
+
resource.load_resource
|
35
171
|
@controller.instance_variable_get(:@ability).should == :some_ability
|
36
172
|
end
|
37
173
|
|
38
|
-
it "should
|
39
|
-
@
|
40
|
-
|
174
|
+
it "should find record through has_one association with :singleton option" do
|
175
|
+
@params.merge!(:action => "show")
|
176
|
+
person = Object.new
|
177
|
+
@controller.instance_variable_set(:@person, person)
|
178
|
+
stub(person).ability { :some_ability }
|
179
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :person, :singleton => true)
|
180
|
+
resource.load_resource
|
41
181
|
@controller.instance_variable_get(:@ability).should == :some_ability
|
42
182
|
end
|
43
183
|
|
44
|
-
it "should
|
184
|
+
it "should build record through has_one association with :singleton option" do
|
185
|
+
@params.merge!(:action => "create", :ability => :ability_attributes)
|
186
|
+
person = Object.new
|
187
|
+
@controller.instance_variable_set(:@person, person)
|
188
|
+
stub(person).build_ability(:ability_attributes) { :new_ability }
|
189
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :person, :singleton => true)
|
190
|
+
resource.load_resource
|
191
|
+
@controller.instance_variable_get(:@ability).should == :new_ability
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should only authorize :read action on parent resource" do
|
195
|
+
@params.merge!(:action => "new", :person_id => 123)
|
196
|
+
stub(Person).find(123) { :some_person }
|
197
|
+
stub(@controller).authorize!(:read, :some_person) { raise CanCan::AccessDenied }
|
198
|
+
resource = CanCan::ControllerResource.new(@controller, :person)
|
199
|
+
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should load the model using a custom class" do
|
203
|
+
@params.merge!(:action => "show", :id => 123)
|
45
204
|
stub(Person).find(123) { :some_resource }
|
46
|
-
CanCan::ControllerResource.new(@controller, :
|
205
|
+
resource = CanCan::ControllerResource.new(@controller, :class => Person)
|
206
|
+
resource.load_resource
|
47
207
|
@controller.instance_variable_get(:@ability).should == :some_resource
|
48
208
|
end
|
49
209
|
|
50
|
-
it "should
|
51
|
-
|
210
|
+
it "should authorize based on resource name if class is false" do
|
211
|
+
@params.merge!(:action => "show", :id => 123)
|
212
|
+
stub(@controller).authorize!(:show, :ability) { raise CanCan::AccessDenied }
|
213
|
+
resource = CanCan::ControllerResource.new(@controller, :class => false)
|
214
|
+
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should load and authorize using custom instance name" do
|
218
|
+
@params.merge!(:action => "show", :id => 123)
|
219
|
+
stub(Ability).find(123) { :some_ability }
|
220
|
+
stub(@controller).authorize!(:show, :some_ability) { raise CanCan::AccessDenied }
|
221
|
+
resource = CanCan::ControllerResource.new(@controller, :instance_name => :custom_ability)
|
222
|
+
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
223
|
+
@controller.instance_variable_get(:@custom_ability).should == :some_ability
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should load resource using custom find_by attribute" do
|
227
|
+
@params.merge!(:action => "show", :id => 123)
|
228
|
+
stub(Ability).find_by_name!(123) { :some_resource }
|
229
|
+
resource = CanCan::ControllerResource.new(@controller, :find_by => :name)
|
230
|
+
resource.load_resource
|
231
|
+
@controller.instance_variable_get(:@ability).should == :some_resource
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should raise ImplementationRemoved when adding :name option" do
|
235
|
+
lambda {
|
236
|
+
CanCan::ControllerResource.new(@controller, :name => :foo)
|
237
|
+
}.should raise_error(CanCan::ImplementationRemoved)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do
|
241
|
+
lambda {
|
242
|
+
CanCan::ControllerResource.new(@controller, :resource => Person)
|
243
|
+
}.should raise_error(CanCan::ImplementationRemoved)
|
52
244
|
end
|
53
245
|
|
54
|
-
it "should raise
|
246
|
+
it "should raise ImplementationRemoved exception when passing :nested option" do
|
55
247
|
lambda {
|
56
|
-
CanCan::ControllerResource.new(@controller, :
|
248
|
+
CanCan::ControllerResource.new(@controller, :nested => :person)
|
57
249
|
}.should raise_error(CanCan::ImplementationRemoved)
|
58
250
|
end
|
59
251
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CanCan::Query do
|
4
|
+
before(:each) do
|
5
|
+
@ability = Object.new
|
6
|
+
@ability.extend(CanCan::Ability)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have false conditions if no abilities match" do
|
10
|
+
@ability.query(:destroy, Person).conditions.should == "true=false"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return hash for single `can` definition" do
|
14
|
+
@ability.can :read, Person, :blocked => false, :user_id => 1
|
15
|
+
@ability.query(:read, Person).conditions.should == { :blocked => false, :user_id => 1 }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should merge multiple can definitions into single SQL string joining with OR" do
|
19
|
+
@ability.can :read, Person, :blocked => false
|
20
|
+
@ability.can :read, Person, :admin => true
|
21
|
+
@ability.query(:read, Person).conditions.should == "(admin=true) OR (blocked=false)"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should merge multiple can definitions into single SQL string joining with OR and AND" do
|
25
|
+
@ability.can :read, Person, :blocked => false, :active => true
|
26
|
+
@ability.can :read, Person, :admin => true
|
27
|
+
@ability.query(:read, Person).conditions.should orderlessly_match("(blocked=false AND active=true) OR (admin=true)")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should merge multiple can definitions into single SQL string joining with OR and AND" do
|
31
|
+
@ability.can :read, Person, :blocked => false, :active => true
|
32
|
+
@ability.can :read, Person, :admin => true
|
33
|
+
@ability.query(:read, Person).conditions.should orderlessly_match("(blocked=false AND active=true) OR (admin=true)")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return false conditions for cannot clause" do
|
37
|
+
@ability.cannot :read, Person
|
38
|
+
@ability.query(:read, Person).conditions.should == "true=false"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return SQL for single `can` definition in front of default `cannot` condition" do
|
42
|
+
@ability.cannot :read, Person
|
43
|
+
@ability.can :read, Person, :blocked => false, :user_id => 1
|
44
|
+
@ability.query(:read, Person).conditions.should orderlessly_match("blocked=false AND user_id=1")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return true condition for single `can` definition in front of default `can` condition" do
|
48
|
+
@ability.can :read, Person
|
49
|
+
@ability.can :read, Person, :blocked => false, :user_id => 1
|
50
|
+
@ability.query(:read, Person).conditions.should == 'true=true'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return false condition for single `cannot` definition" do
|
54
|
+
@ability.cannot :read, Person, :blocked => true, :user_id => 1
|
55
|
+
@ability.query(:read, Person).conditions.should == 'true=false'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return `false condition` for single `cannot` definition in front of default `cannot` condition" do
|
59
|
+
@ability.cannot :read, Person
|
60
|
+
@ability.cannot :read, Person, :blocked => true, :user_id => 1
|
61
|
+
@ability.query(:read, Person).conditions.should == 'true=false'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return `not (sql)` for single `cannot` definition in front of default `can` condition" do
|
65
|
+
@ability.can :read, Person
|
66
|
+
@ability.cannot :read, Person, :blocked => true, :user_id => 1
|
67
|
+
@ability.query(:read, Person).conditions.should orderlessly_match("not (blocked=true AND user_id=1)")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return appropriate sql conditions in complex case" do
|
71
|
+
@ability.can :read, Person
|
72
|
+
@ability.can :manage, Person, :id => 1
|
73
|
+
@ability.can :update, Person, :manager_id => 1
|
74
|
+
@ability.cannot :update, Person, :self_managed => true
|
75
|
+
@ability.query(:update, Person).conditions.should == 'not (self_managed=true) AND ((manager_id=1) OR (id=1))'
|
76
|
+
@ability.query(:manage, Person).conditions.should == {:id=>1}
|
77
|
+
@ability.query(:read, Person).conditions.should == 'true=true'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should have nil joins if no can definitions" do
|
81
|
+
@ability.query(:read, Person).joins.should be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should have nil joins if no nested hashes specified in conditions" do
|
85
|
+
@ability.can :read, Person, :blocked => false
|
86
|
+
@ability.can :read, Person, :admin => true
|
87
|
+
@ability.query(:read, Person).joins.should be_nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should merge separate joins into a single array" do
|
91
|
+
@ability.can :read, Person, :project => { :blocked => false }
|
92
|
+
@ability.can :read, Person, :company => { :admin => true }
|
93
|
+
@ability.query(:read, Person).joins.inspect.should orderlessly_match([:company, :project].inspect)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should merge same joins into a single array" do
|
97
|
+
@ability.can :read, Person, :project => { :blocked => false }
|
98
|
+
@ability.can :read, Person, :project => { :admin => true }
|
99
|
+
@ability.query(:read, Person).joins.should == [:project]
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should merge complex, nested joins" do
|
103
|
+
@ability.can :read, Person, :project => { :bar => {:test => true} }, :company => { :bar => {:test => true} }
|
104
|
+
@ability.can :read, Person, :project => { :foo => {:bar => true}, :bar => {:zip => :zap} }
|
105
|
+
@ability.query(:read, Person).joins.inspect.should orderlessly_match([{:project => [:bar, :foo]}, {:company => [:bar]}].inspect)
|
106
|
+
end
|
107
|
+
end
|