cancan 1.6.0 → 1.6.10

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.
@@ -20,7 +20,7 @@ describe CanCan::ControllerResource do
20
20
  end
21
21
 
22
22
  it "should not load resource into an instance variable if already set" do
23
- @params.merge!(:action => "show", :id => 123)
23
+ @params.merge!(:action => "show", :id => "123")
24
24
  @controller.instance_variable_set(:@project, :some_project)
25
25
  resource = CanCan::ControllerResource.new(@controller)
26
26
  resource.load_resource
@@ -35,6 +35,30 @@ describe CanCan::ControllerResource do
35
35
  @controller.instance_variable_get(:@project).should == project
36
36
  end
37
37
 
38
+ it "should attempt to load a resource with the same namespace as the controller when using :: for namespace" do
39
+ module MyEngine
40
+ class Project < ::Project; end
41
+ end
42
+
43
+ project = MyEngine::Project.create!
44
+ @params.merge!(:controller => "MyEngine::ProjectsController", :action => "show", :id => project.id)
45
+ resource = CanCan::ControllerResource.new(@controller)
46
+ resource.load_resource
47
+ @controller.instance_variable_get(:@project).should == project
48
+ end
49
+
50
+ # Rails includes namespace in params, see issue #349
51
+ it "should create through the namespaced params" do
52
+ module MyEngine
53
+ class Project < ::Project; end
54
+ end
55
+
56
+ @params.merge!(:controller => "MyEngine::ProjectsController", :action => "create", :my_engine_project => {:name => "foobar"})
57
+ resource = CanCan::ControllerResource.new(@controller)
58
+ resource.load_resource
59
+ @controller.instance_variable_get(:@project).name.should == "foobar"
60
+ end
61
+
38
62
  it "should properly load resource for namespaced controller when using '::' for namespace" do
39
63
  project = Project.create!
40
64
  @params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
@@ -43,6 +67,16 @@ describe CanCan::ControllerResource do
43
67
  @controller.instance_variable_get(:@project).should == project
44
68
  end
45
69
 
70
+ it "has the specified nested resource_class when using / for namespace" do
71
+ module Admin
72
+ class Dashboard; end
73
+ end
74
+ @ability.can(:index, "admin/dashboard")
75
+ @params.merge!(:controller => "admin/dashboard", :action => "index")
76
+ resource = CanCan::ControllerResource.new(@controller, :authorize => true)
77
+ resource.send(:resource_class).should == Admin::Dashboard
78
+ end
79
+
46
80
  it "should build a new resource with hash if params[:id] is not specified" do
47
81
  @params.merge!(:action => "create", :project => {:name => "foobar"})
48
82
  resource = CanCan::ControllerResource.new(@controller)
@@ -50,6 +84,20 @@ describe CanCan::ControllerResource do
50
84
  @controller.instance_variable_get(:@project).name.should == "foobar"
51
85
  end
52
86
 
87
+ it "should build a new resource for namespaced model with hash if params[:id] is not specified" do
88
+ @params.merge!(:action => "create", 'sub_project' => {:name => "foobar"})
89
+ resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
90
+ resource.load_resource
91
+ @controller.instance_variable_get(:@project).name.should == "foobar"
92
+ end
93
+
94
+ it "should build a new resource for namespaced controller and namespaced model with hash if params[:id] is not specified" do
95
+ @params.merge!(:controller => "Admin::SubProjectsController", :action => "create", 'sub_project' => {:name => "foobar"})
96
+ resource = CanCan::ControllerResource.new(@controller, :class => Project)
97
+ resource.load_resource
98
+ @controller.instance_variable_get(:@sub_project).name.should == "foobar"
99
+ end
100
+
53
101
  it "should build a new resource with attributes from current ability" do
54
102
  @params.merge!(:action => "new")
55
103
  @ability.can(:create, Project, :name => "from conditions")
@@ -104,13 +152,13 @@ describe CanCan::ControllerResource do
104
152
  it "should authorize parent resource in collection action" do
105
153
  @params[:action] = "index"
106
154
  @controller.instance_variable_set(:@category, :some_category)
107
- stub(@controller).authorize!(:read, :some_category) { raise CanCan::AccessDenied }
155
+ stub(@controller).authorize!(:show, :some_category) { raise CanCan::AccessDenied }
108
156
  resource = CanCan::ControllerResource.new(@controller, :category, :parent => true)
109
157
  lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
110
158
  end
111
159
 
112
160
  it "should perform authorization using controller action and loaded model" do
113
- @params.merge!(:action => "show", :id => 123)
161
+ @params.merge!(:action => "show", :id => "123")
114
162
  @controller.instance_variable_set(:@project, :some_project)
115
163
  stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied }
116
164
  resource = CanCan::ControllerResource.new(@controller)
@@ -118,14 +166,14 @@ describe CanCan::ControllerResource do
118
166
  end
119
167
 
120
168
  it "should perform authorization using controller action and non loaded model" do
121
- @params.merge!(:action => "show", :id => 123)
169
+ @params.merge!(:action => "show", :id => "123")
122
170
  stub(@controller).authorize!(:show, Project) { raise CanCan::AccessDenied }
123
171
  resource = CanCan::ControllerResource.new(@controller)
124
172
  lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
125
173
  end
126
174
 
127
175
  it "should call load_resource and authorize_resource for load_and_authorize_resource" do
128
- @params.merge!(:action => "show", :id => 123)
176
+ @params.merge!(:action => "show", :id => "123")
129
177
  resource = CanCan::ControllerResource.new(@controller)
130
178
  mock(resource).load_resource
131
179
  mock(resource).authorize_resource
@@ -133,7 +181,7 @@ describe CanCan::ControllerResource do
133
181
  end
134
182
 
135
183
  it "should not build a single resource when on custom collection action even with id" do
136
- @params.merge!(:action => "sort", :id => 123)
184
+ @params.merge!(:action => "sort", :id => "123")
137
185
  resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
138
186
  resource.load_resource
139
187
  @controller.instance_variable_get(:@project).should be_nil
@@ -149,7 +197,7 @@ describe CanCan::ControllerResource do
149
197
  end
150
198
 
151
199
  it "should build a resource when on custom new action even when params[:id] exists" do
152
- @params.merge!(:action => "build", :id => 123)
200
+ @params.merge!(:action => "build", :id => "123")
153
201
  stub(Project).new { :some_project }
154
202
  resource = CanCan::ControllerResource.new(@controller, :new => :build)
155
203
  resource.load_resource
@@ -183,39 +231,47 @@ describe CanCan::ControllerResource do
183
231
  resource.should_not be_parent
184
232
  end
185
233
 
234
+ it "should have the specified resource_class if 'name' is passed to load_resource" do
235
+ class Section
236
+ end
237
+
238
+ resource = CanCan::ControllerResource.new(@controller, :section)
239
+ resource.send(:resource_class).should == Section
240
+ end
241
+
186
242
  it "should load parent resource through proper id parameter" do
187
243
  project = Project.create!
188
- @params.merge!(:action => "index", :project_id => project.id)
189
- resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
244
+ @params.merge!(:controller => "categories", :action => "index", :project_id => project.id)
245
+ resource = CanCan::ControllerResource.new(@controller, :project)
190
246
  resource.load_resource
191
247
  @controller.instance_variable_get(:@project).should == project
192
248
  end
193
249
 
194
250
  it "should load resource through the association of another parent resource using instance variable" do
195
- @params.merge!(:action => "show", :id => 123)
251
+ @params.merge!(:action => "show", :id => "123")
196
252
  category = Object.new
197
253
  @controller.instance_variable_set(:@category, category)
198
- stub(category).projects.stub!.find(123) { :some_project }
254
+ stub(category).projects.stub!.find("123") { :some_project }
199
255
  resource = CanCan::ControllerResource.new(@controller, :through => :category)
200
256
  resource.load_resource
201
257
  @controller.instance_variable_get(:@project).should == :some_project
202
258
  end
203
259
 
204
260
  it "should load resource through the custom association name" do
205
- @params.merge!(:action => "show", :id => 123)
261
+ @params.merge!(:action => "show", :id => "123")
206
262
  category = Object.new
207
263
  @controller.instance_variable_set(:@category, category)
208
- stub(category).custom_projects.stub!.find(123) { :some_project }
264
+ stub(category).custom_projects.stub!.find("123") { :some_project }
209
265
  resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects)
210
266
  resource.load_resource
211
267
  @controller.instance_variable_get(:@project).should == :some_project
212
268
  end
213
269
 
214
270
  it "should load resource through the association of another parent resource using method" do
215
- @params.merge!(:action => "show", :id => 123)
271
+ @params.merge!(:action => "show", :id => "123")
216
272
  category = Object.new
217
273
  stub(@controller).category { category }
218
- stub(category).projects.stub!.find(123) { :some_project }
274
+ stub(category).projects.stub!.find("123") { :some_project }
219
275
  resource = CanCan::ControllerResource.new(@controller, :through => :category)
220
276
  resource.load_resource
221
277
  @controller.instance_variable_get(:@project).should == :some_project
@@ -235,7 +291,10 @@ describe CanCan::ControllerResource do
235
291
  resource = CanCan::ControllerResource.new(@controller, :through => :category)
236
292
  lambda {
237
293
  resource.load_resource
238
- }.should raise_error(CanCan::AccessDenied)
294
+ }.should raise_error(CanCan::AccessDenied) { |exception|
295
+ exception.action.should == :show
296
+ exception.subject.should == Project
297
+ }
239
298
  @controller.instance_variable_get(:@project).should be_nil
240
299
  end
241
300
 
@@ -249,17 +308,17 @@ describe CanCan::ControllerResource do
249
308
  end
250
309
 
251
310
  it "should load through first matching if multiple are given" do
252
- @params.merge!(:action => "show", :id => 123)
311
+ @params.merge!(:action => "show", :id => "123")
253
312
  category = Object.new
254
313
  @controller.instance_variable_set(:@category, category)
255
- stub(category).projects.stub!.find(123) { :some_project }
314
+ stub(category).projects.stub!.find("123") { :some_project }
256
315
  resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user])
257
316
  resource.load_resource
258
317
  @controller.instance_variable_get(:@project).should == :some_project
259
318
  end
260
319
 
261
- it "should find record through has_one association with :singleton option" do
262
- @params.merge!(:action => "show", :id => 123)
320
+ it "should find record through has_one association with :singleton option without id param" do
321
+ @params.merge!(:action => "show", :id => nil)
263
322
  category = Object.new
264
323
  @controller.instance_variable_set(:@category, category)
265
324
  stub(category).project { :some_project }
@@ -268,14 +327,14 @@ describe CanCan::ControllerResource do
268
327
  @controller.instance_variable_get(:@project).should == :some_project
269
328
  end
270
329
 
271
- it "should build record through has_one association with :singleton option" do
330
+ it "should not build record through has_one association with :singleton option because it can cause it to delete it in the database" do
272
331
  @params.merge!(:action => "create", :project => {:name => "foobar"})
273
- category = Object.new
332
+ category = Category.new
274
333
  @controller.instance_variable_set(:@category, category)
275
- stub(category).build_project { |attributes| Project.new(attributes) }
276
334
  resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true)
277
335
  resource.load_resource
278
336
  @controller.instance_variable_get(:@project).name.should == "foobar"
337
+ @controller.instance_variable_get(:@project).category.should == category
279
338
  end
280
339
 
281
340
  it "should find record through has_one association with :singleton and :shallow options" do
@@ -293,10 +352,10 @@ describe CanCan::ControllerResource do
293
352
  @controller.instance_variable_get(:@project).name.should == "foobar"
294
353
  end
295
354
 
296
- it "should only authorize :read action on parent resource" do
355
+ it "should only authorize :show action on parent resource" do
297
356
  project = Project.create!
298
357
  @params.merge!(:action => "new", :project_id => project.id)
299
- stub(@controller).authorize!(:read, project) { raise CanCan::AccessDenied }
358
+ stub(@controller).authorize!(:show, project) { raise CanCan::AccessDenied }
300
359
  resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
301
360
  lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
302
361
  end
@@ -309,8 +368,16 @@ describe CanCan::ControllerResource do
309
368
  @controller.instance_variable_get(:@project).should == project
310
369
  end
311
370
 
371
+ it "should load the model using a custom namespaced class" do
372
+ project = Sub::Project.create!
373
+ @params.merge!(:action => "show", :id => project.id)
374
+ resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
375
+ resource.load_resource
376
+ @controller.instance_variable_get(:@project).should == project
377
+ end
378
+
312
379
  it "should authorize based on resource name if class is false" do
313
- @params.merge!(:action => "show", :id => 123)
380
+ @params.merge!(:action => "show", :id => "123")
314
381
  stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
315
382
  resource = CanCan::ControllerResource.new(@controller, :class => false)
316
383
  lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
@@ -325,6 +392,21 @@ describe CanCan::ControllerResource do
325
392
  @controller.instance_variable_get(:@custom_project).should == project
326
393
  end
327
394
 
395
+ it "should load resource using custom ID param" do
396
+ project = Project.create!
397
+ @params.merge!(:action => "show", :the_project => project.id)
398
+ resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
399
+ resource.load_resource
400
+ @controller.instance_variable_get(:@project).should == project
401
+ end
402
+
403
+ # CVE-2012-5664
404
+ it "should always convert id param to string" do
405
+ @params.merge!(:action => "show", :the_project => { :malicious => "I am" })
406
+ resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
407
+ resource.send(:id_param).class.should == String
408
+ end
409
+
328
410
  it "should load resource using custom find_by attribute" do
329
411
  project = Project.create!(:name => "foo")
330
412
  @params.merge!(:action => "show", :id => "foo")
@@ -333,6 +415,14 @@ describe CanCan::ControllerResource do
333
415
  @controller.instance_variable_get(:@project).should == project
334
416
  end
335
417
 
418
+ it "should allow full find method to be passed into find_by option" do
419
+ project = Project.create!(:name => "foo")
420
+ @params.merge!(:action => "show", :id => "foo")
421
+ resource = CanCan::ControllerResource.new(@controller, :find_by => :find_by_name)
422
+ resource.load_resource
423
+ @controller.instance_variable_get(:@project).should == project
424
+ end
425
+
336
426
  it "should raise ImplementationRemoved when adding :name option" do
337
427
  lambda {
338
428
  CanCan::ControllerResource.new(@controller, :name => :foo)
@@ -32,4 +32,27 @@ describe CanCan::AccessDenied do
32
32
  @exception.message.should == "Access denied!"
33
33
  end
34
34
  end
35
+
36
+ describe "i18n in the default message" do
37
+ after(:each) do
38
+ I18n.backend = nil
39
+ end
40
+
41
+ it "uses i18n for the default message" do
42
+ I18n.backend.store_translations :en, :unauthorized => {:default => "This is a different message"}
43
+ @exception = CanCan::AccessDenied.new
44
+ @exception.message.should == "This is a different message"
45
+ end
46
+
47
+ it "defaults to a nice message" do
48
+ @exception = CanCan::AccessDenied.new
49
+ @exception.message.should == "You are not authorized to access this page."
50
+ end
51
+
52
+ it "does not use translation if a message is given" do
53
+ @exception = CanCan::AccessDenied.new("Hey! You're not welcome here")
54
+ @exception.message.should == "Hey! You're not welcome here"
55
+ @exception.message.should_not == "You are not authorized to access this page."
56
+ end
57
+ end
35
58
  end
@@ -32,11 +32,29 @@ describe CanCan::InheritedResource do
32
32
  @controller.instance_variable_get(:@project).should == :project_resource
33
33
  end
34
34
 
35
- it "index should load through @controller.collection" do
35
+ it "index should load through @controller.end_of_association_chain" do
36
36
  @params[:action] = "index"
37
37
  stub(Project).accessible_by(@ability, :index) { :projects }
38
- stub(@controller).collection { Project }
38
+ stub(@controller).end_of_association_chain { Project }
39
39
  CanCan::InheritedResource.new(@controller).load_resource
40
40
  @controller.instance_variable_get(:@projects).should == :projects
41
41
  end
42
+
43
+ it "should build a new resource with attributes from current ability" do
44
+ @params[:action] = "new"
45
+ @ability.can(:create, Project, :name => "from conditions")
46
+ stub(@controller).build_resource { Struct.new(:name).new }
47
+ resource = CanCan::InheritedResource.new(@controller)
48
+ resource.load_resource
49
+ @controller.instance_variable_get(:@project).name.should == "from conditions"
50
+ end
51
+
52
+ it "should override initial attributes with params" do
53
+ @params.merge!(:action => "new", :project => {:name => "from params"})
54
+ @ability.can(:create, Project, :name => "from conditions")
55
+ stub(@controller).build_resource { Struct.new(:name).new }
56
+ resource = CanCan::ControllerResource.new(@controller)
57
+ resource.load_resource
58
+ @controller.instance_variable_get(:@project).name.should == "from params"
59
+ end
42
60
  end
@@ -1,10 +1,6 @@
1
1
  if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
2
2
  require "spec_helper"
3
3
 
4
- RSpec.configure do |config|
5
- config.extend WithModel
6
- end
7
-
8
4
  ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
9
5
 
10
6
  describe CanCan::ModelAdapters::ActiveRecordAdapter do
@@ -24,10 +20,12 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
24
20
  t.boolean "secret"
25
21
  t.integer "priority"
26
22
  t.integer "category_id"
23
+ t.integer "user_id"
27
24
  end
28
25
  model do
29
26
  belongs_to :category
30
27
  has_many :comments
28
+ belongs_to :user
31
29
  end
32
30
  end
33
31
 
@@ -41,6 +39,15 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
41
39
  end
42
40
  end
43
41
 
42
+ with_model :user do
43
+ table do |t|
44
+
45
+ end
46
+ model do
47
+ has_many :articles
48
+ end
49
+ end
50
+
44
51
  before(:each) do
45
52
  Article.delete_all
46
53
  Comment.delete_all
@@ -56,6 +63,11 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
56
63
  CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::ActiveRecordAdapter
57
64
  end
58
65
 
66
+ it "should find record" do
67
+ article = Article.create!
68
+ CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id).should == article
69
+ end
70
+
59
71
  it "should not fetch any records when no abilities are defined" do
60
72
  Article.create!
61
73
  Article.accessible_by(@ability).should be_empty
@@ -125,6 +137,15 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
125
137
  Article.accessible_by(@ability).should == [article1]
126
138
  end
127
139
 
140
+ it "should fetch only associated records when using with a scope for conditions" do
141
+ @ability.can :read, Article, Article.where(:secret => true)
142
+ category1 = Category.create!(:visible => false)
143
+ category2 = Category.create!(:visible => true)
144
+ article1 = Article.create!(:secret => true, :category => category1)
145
+ article2 = Article.create!(:secret => true, :category => category2)
146
+ category1.articles.accessible_by(@ability).should == [article1]
147
+ end
148
+
128
149
  it "should raise an exception when trying to merge scope with other conditions" do
129
150
  @ability.can :read, Article, :published => true
130
151
  @ability.can :read, Article, Article.where(:secret => true)
@@ -186,6 +207,16 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
186
207
  @ability.model_adapter(Article, :read).conditions.should == "'t'='t'"
187
208
  end
188
209
 
210
+ it "should return appropriate sql conditions in complex case with nested joins" do
211
+ @ability.can :read, Comment, :article => { :category => { :visible => true } }
212
+ @ability.model_adapter(Comment, :read).conditions.should == { Category.table_name.to_sym => { :visible => true } }
213
+ end
214
+
215
+ it "should return appropriate sql conditions in complex case with nested joins of different depth" do
216
+ @ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } }
217
+ @ability.model_adapter(Comment, :read).conditions.should == { Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } }
218
+ end
219
+
189
220
  it "should not forget conditions when calling with SQL string" do
190
221
  @ability.can :read, Article, :published => true
191
222
  @ability.can :read, Article, ['secret=?', false]
@@ -217,6 +248,21 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
217
248
  @ability.model_adapter(Article, :read).joins.should == [:project]
218
249
  end
219
250
 
251
+ it "should merge nested and non-nested joins" do
252
+ @ability.can :read, Article, :project => { :blocked => false }
253
+ @ability.can :read, Article, :project => { :comments => { :spam => true } }
254
+ @ability.model_adapter(Article, :read).joins.should == [{:project=>[:comments]}]
255
+ end
256
+
257
+ it "should merge :all conditions with other conditions" do
258
+ user = User.create!
259
+ article = Article.create!(:user => user)
260
+ ability = Ability.new(user)
261
+ ability.can :manage, :all
262
+ ability.can :manage, Article, :user_id => user.id
263
+ Article.accessible_by(ability).should == [article]
264
+ end
265
+
220
266
  it "should restrict articles given a MetaWhere condition" do
221
267
  @ability.can :read, Article, :priority.lt => 2
222
268
  article1 = Article.create!(:priority => 1)
@@ -226,6 +272,16 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
226
272
  @ability.should_not be_able_to(:read, article2)
227
273
  end
228
274
 
275
+ it "should merge MetaWhere and non-MetaWhere conditions" do
276
+ @ability.can :read, Article, :priority.lt => 2
277
+ @ability.can :read, Article, :priority => 1
278
+ article1 = Article.create!(:priority => 1)
279
+ article2 = Article.create!(:priority => 3)
280
+ Article.accessible_by(@ability).should == [article1]
281
+ @ability.should be_able_to(:read, article1)
282
+ @ability.should_not be_able_to(:read, article2)
283
+ end
284
+
229
285
  it "should match any MetaWhere condition" do
230
286
  adapter = CanCan::ModelAdapters::ActiveRecordAdapter
231
287
  article1 = Article.new(:priority => 1, :name => "Hello World")
@@ -256,8 +312,9 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
256
312
  adapter.matches_condition?(article1, :name.like, "%helo%").should be_false
257
313
  adapter.matches_condition?(article1, :name.like, "hello").should be_false
258
314
  adapter.matches_condition?(article1, :name.like, "hello.world").should be_false
259
- adapter.matches_condition?(article1, :name.nlike, "%helo%").should be_true
260
- adapter.matches_condition?(article1, :name.nlike, "%ello worl%").should be_false
315
+ # For some reason this is reporting "The not_matches MetaWhere condition is not supported."
316
+ # adapter.matches_condition?(article1, :name.nlike, "%helo%").should be_true
317
+ # adapter.matches_condition?(article1, :name.nlike, "%ello worl%").should be_false
261
318
  end
262
319
  end
263
320
  end
@@ -36,6 +36,11 @@ if ENV["MODEL_ADAPTER"] == "data_mapper"
36
36
  CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::DataMapperAdapter
37
37
  end
38
38
 
39
+ it "should find record" do
40
+ article = Article.create
41
+ CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id).should == article
42
+ end
43
+
39
44
  it "should not fetch any records when no abilities are defined" do
40
45
  Article.create
41
46
  Article.accessible_by(@ability).should be_empty
@@ -65,7 +70,6 @@ if ENV["MODEL_ADAPTER"] == "data_mapper"
65
70
  end
66
71
 
67
72
  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
73
  @ability.can :read, Article, :published => true
70
74
  @ability.cannot :read, Article, :secret => true
71
75
  article1 = Article.create(:published => true, :secret => false)
@@ -36,12 +36,26 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
36
36
  CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject).should == CanCan::ModelAdapters::MongoidAdapter
37
37
  end
38
38
 
39
+ it "should find record" do
40
+ project = MongoidProject.create
41
+ CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id).should == project
42
+ end
43
+
39
44
  it "should compare properties on mongoid documents with the conditions hash" do
40
45
  model = MongoidProject.new
41
46
  @ability.can :read, MongoidProject, :id => model.id
42
47
  @ability.should be_able_to(:read, model)
43
48
  end
44
49
 
50
+ it "should be able to read hashes when field is array" do
51
+ one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three'])
52
+ two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five'])
53
+
54
+ @ability.can :foo, MongoidProject, :numbers => 'one'
55
+ @ability.should be_able_to(:foo, one_to_three)
56
+ @ability.should_not be_able_to(:foo, two_to_five)
57
+ end
58
+
45
59
  it "should return [] when no ability is defined so no records are found" do
46
60
  MongoidProject.create(:title => 'Sir')
47
61
  MongoidProject.create(:title => 'Lord')
@@ -59,6 +73,26 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
59
73
  MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
60
74
  end
61
75
 
76
+ it "should return the correct records when a mix of can and cannot rules in defined ability" do
77
+ @ability.can :manage, MongoidProject, :title => 'Sir'
78
+ @ability.cannot :destroy, MongoidProject
79
+
80
+ sir = MongoidProject.create(:title => 'Sir')
81
+ lord = MongoidProject.create(:title => 'Lord')
82
+ dude = MongoidProject.create(:title => 'Dude')
83
+
84
+ MongoidProject.accessible_by(@ability, :destroy).entries.should == [sir]
85
+ end
86
+
87
+ it "should be able to mix empty conditions and hashes" do
88
+ @ability.can :read, MongoidProject
89
+ @ability.can :read, MongoidProject, :title => 'Sir'
90
+ sir = MongoidProject.create(:title => 'Sir')
91
+ lord = MongoidProject.create(:title => 'Lord')
92
+
93
+ MongoidProject.accessible_by(@ability, :read).count.should == 2
94
+ end
95
+
62
96
  it "should return everything when the defined ability is manage all" do
63
97
  @ability.can :manage, :all
64
98
  sir = MongoidProject.create(:title => 'Sir')
@@ -68,6 +102,14 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
68
102
  MongoidProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
69
103
  end
70
104
 
105
+ it "should allow a scope for conditions" do
106
+ @ability.can :read, MongoidProject, MongoidProject.where(:title => 'Sir')
107
+ sir = MongoidProject.create(:title => 'Sir')
108
+ lord = MongoidProject.create(:title => 'Lord')
109
+ dude = MongoidProject.create(:title => 'Dude')
110
+
111
+ MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
112
+ end
71
113
 
72
114
  describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
73
115
  it "should handle :field.in" do
@@ -154,7 +196,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
154
196
  @ability.can :read, MongoidProject, :foo => {:bar => 1}
155
197
  MongoidProject.accessible_by(@ability, :read).entries.first.should == obj
156
198
  end
157
-
199
+
158
200
  it "should exclude from the result if set to cannot" do
159
201
  obj = MongoidProject.create(:bar => 1)
160
202
  obj2 = MongoidProject.create(:bar => 2)
@@ -171,7 +213,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
171
213
  @ability.can :read, MongoidProject, :bar => 2
172
214
  MongoidProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2]
173
215
  end
174
-
216
+
175
217
  it "should not allow to fetch records when ability with just block present" do
176
218
  @ability.can :read, MongoidProject do
177
219
  false
@@ -1,4 +1,5 @@
1
1
  require "spec_helper"
2
+ require "ostruct" # for OpenStruct below
2
3
 
3
4
  # Most of Rule functionality is tested in Ability specs
4
5
  describe CanCan::Rule do
@@ -36,4 +37,16 @@ describe CanCan::Rule do
36
37
  rule = CanCan::Rule.new(true, :read, Integer, nil, nil)
37
38
  rule.associations_hash.should == {}
38
39
  end
40
+
41
+ it "should not be mergeable if conditions are not simple hashes" do
42
+ meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test')
43
+ @conditions[meta_where] = :bar
44
+
45
+ @rule.should be_unmergeable
46
+ end
47
+
48
+ it "should be mergeable if conditions is an empty hash" do
49
+ @conditions = {}
50
+ @rule.should_not be_unmergeable
51
+ end
39
52
  end