cancancan 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,60 +1,71 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe CanCan::InheritedResource do
4
+ let(:ability) { Ability.new(nil) }
5
+ let(:params) { HashWithIndifferentAccess.new(:controller => "models") }
6
+ let(:controller_class) { Class.new }
7
+ let(:controller) { controller_class.new }
8
+
4
9
  before(:each) do
5
- @params = HashWithIndifferentAccess.new(:controller => "projects")
6
- @controller_class = Class.new
7
- @controller = @controller_class.new
8
- @ability = Ability.new(nil)
9
- allow(@controller).to receive(:params).and_return { @params }
10
- allow(@controller).to receive(:current_ability) { @ability }
11
- allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} }
10
+ class Model
11
+ attr_accessor :name
12
+
13
+ def initialize(attributes={})
14
+ attributes.each do |attribute, value|
15
+ send("#{attribute}=", value)
16
+ end
17
+ end
18
+ end
19
+
20
+ allow(controller).to receive(:params) { params }
21
+ allow(controller).to receive(:current_ability) { ability }
22
+ allow(controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} }
12
23
  end
13
24
 
14
- it "show loads resource through @controller.resource" do
15
- @params.merge!(:action => "show", :id => 123)
16
- allow(@controller).to receive(:resource) { :project_resource }
17
- CanCan::InheritedResource.new(@controller).load_resource
18
- expect(@controller.instance_variable_get(:@project)).to eq(:project_resource)
25
+ it "show loads resource through controller.resource" do
26
+ params.merge!(:action => "show", :id => 123)
27
+ allow(controller).to receive(:resource) { :model_resource }
28
+ CanCan::InheritedResource.new(controller).load_resource
29
+ expect(controller.instance_variable_get(:@model)).to eq(:model_resource)
19
30
  end
20
31
 
21
- it "new loads through @controller.build_resource" do
22
- @params[:action] = "new"
23
- allow(@controller).to receive(:build_resource) { :project_resource }
24
- CanCan::InheritedResource.new(@controller).load_resource
25
- expect(@controller.instance_variable_get(:@project)).to eq(:project_resource)
32
+ it "new loads through controller.build_resource" do
33
+ params[:action] = "new"
34
+ allow(controller).to receive(:build_resource) { :model_resource }
35
+ CanCan::InheritedResource.new(controller).load_resource
36
+ expect(controller.instance_variable_get(:@model)).to eq(:model_resource)
26
37
  end
27
38
 
28
- it "index loads through @controller.association_chain when parent" do
29
- @params[:action] = "index"
30
- allow(@controller).to receive(:association_chain) { @controller.instance_variable_set(:@project, :project_resource) }
31
- CanCan::InheritedResource.new(@controller, :parent => true).load_resource
32
- expect(@controller.instance_variable_get(:@project)).to eq(:project_resource)
39
+ it "index loads through controller.association_chain when parent" do
40
+ params[:action] = "index"
41
+ allow(controller).to receive(:association_chain) { controller.instance_variable_set(:@model, :model_resource) }
42
+ CanCan::InheritedResource.new(controller, :parent => true).load_resource
43
+ expect(controller.instance_variable_get(:@model)).to eq(:model_resource)
33
44
  end
34
45
 
35
- it "index loads through @controller.end_of_association_chain" do
36
- @params[:action] = "index"
37
- allow(Project).to receive(:accessible_by).with(@ability, :index) { :projects }
38
- allow(@controller).to receive(:end_of_association_chain) { Project }
39
- CanCan::InheritedResource.new(@controller).load_resource
40
- expect(@controller.instance_variable_get(:@projects)).to eq(:projects)
46
+ it "index loads through controller.end_of_association_chain" do
47
+ params[:action] = "index"
48
+ allow(Model).to receive(:accessible_by).with(ability, :index) { :projects }
49
+ allow(controller).to receive(:end_of_association_chain) { Model }
50
+ CanCan::InheritedResource.new(controller).load_resource
51
+ expect(controller.instance_variable_get(:@models)).to eq(:projects)
41
52
  end
42
53
 
43
54
  it "builds a new resource with attributes from current ability" do
44
- @params[:action] = "new"
45
- @ability.can(:create, Project, :name => "from conditions")
46
- allow(@controller).to receive(:build_resource) { Struct.new(:name).new }
47
- resource = CanCan::InheritedResource.new(@controller)
55
+ params[:action] = "new"
56
+ ability.can(:create, Model, :name => "from conditions")
57
+ allow(controller).to receive(:build_resource) { Struct.new(:name).new }
58
+ resource = CanCan::InheritedResource.new(controller)
48
59
  resource.load_resource
49
- expect(@controller.instance_variable_get(:@project).name).to eq("from conditions")
60
+ expect(controller.instance_variable_get(:@model).name).to eq("from conditions")
50
61
  end
51
62
 
52
63
  it "overrides initial attributes with params" do
53
- @params.merge!(:action => "new", :project => {:name => "from params"})
54
- @ability.can(:create, Project, :name => "from conditions")
55
- allow(@controller).to receive(:build_resource) { Struct.new(:name).new }
56
- resource = CanCan::ControllerResource.new(@controller)
64
+ params.merge!(:action => "new", :model => {:name => "from params"})
65
+ ability.can(:create, Model, :name => "from conditions")
66
+ allow(controller).to receive(:build_resource) { Struct.new(:name).new }
67
+ resource = CanCan::ControllerResource.new(controller)
57
68
  resource.load_resource
58
- expect(@controller.instance_variable_get(:@project).name).to eq("from params")
69
+ expect(controller.instance_variable_get(:@model).name).to eq("from params")
59
70
  end
60
71
  end
@@ -2,61 +2,65 @@ require "spec_helper"
2
2
 
3
3
  if defined? CanCan::ModelAdapters::ActiveRecordAdapter
4
4
 
5
- RSpec.configure do |config|
6
- config.extend WithModel
7
- end
5
+ describe CanCan::ModelAdapters::ActiveRecordAdapter do
8
6
 
9
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
7
+ before :each do
8
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
9
+ ActiveRecord::Migration.verbose = false
10
+ ActiveRecord::Schema.define do
11
+ create_table(:categories) do |t|
12
+ t.string :name
13
+ t.boolean :visible
14
+ t.timestamps
15
+ end
16
+
17
+ create_table(:projects) do |t|
18
+ t.string :name
19
+ t.timestamps
20
+ end
21
+
22
+ create_table(:articles) do |t|
23
+ t.string :name
24
+ t.timestamps
25
+ t.boolean :published
26
+ t.boolean :secret
27
+ t.integer :priority
28
+ t.integer :category_id
29
+ t.integer :user_id
30
+ end
31
+
32
+ create_table(:comments) do |t|
33
+ t.boolean :spam
34
+ t.integer :article_id
35
+ t.timestamps
36
+ end
37
+
38
+ create_table(:users) do |t|
39
+ t.timestamps
40
+ end
41
+ end
10
42
 
11
- describe CanCan::ModelAdapters::ActiveRecordAdapter do
12
- with_model :category do
13
- table do |t|
14
- t.string "name"
15
- t.boolean "visible"
43
+ class Project < ActiveRecord::Base
16
44
  end
17
- model do
45
+
46
+ class Category < ActiveRecord::Base
18
47
  has_many :articles
19
48
  end
20
- end
21
49
 
22
- with_model :article do
23
- table do |t|
24
- t.string "name"
25
- t.boolean "published"
26
- t.boolean "secret"
27
- t.integer "priority"
28
- t.integer "category_id"
29
- t.integer "user_id"
30
- end
31
- model do
50
+ class Article < ActiveRecord::Base
32
51
  belongs_to :category
33
52
  has_many :comments
34
53
  belongs_to :user
35
54
  end
36
- end
37
55
 
38
- with_model :comment do
39
- table do |t|
40
- t.boolean "spam"
41
- t.integer "article_id"
42
- end
43
- model do
56
+ class Comment < ActiveRecord::Base
44
57
  belongs_to :article
45
58
  end
46
- end
47
59
 
48
- with_model :user do
49
- table do |t|
50
-
51
- end
52
- model do
60
+ class User < ActiveRecord::Base
53
61
  has_many :articles
54
62
  end
55
- end
56
63
 
57
- before(:each) do
58
- Article.delete_all
59
- Comment.delete_all
60
64
  (@ability = double).extend(CanCan::Ability)
61
65
  @article_table = Article.table_name
62
66
  @comment_table = Comment.table_name
@@ -295,60 +299,6 @@ if defined? CanCan::ModelAdapters::ActiveRecordAdapter
295
299
  expect(Article.accessible_by(ability)).to eq([article])
296
300
  end
297
301
 
298
- it "restricts articles given a MetaWhere condition" do
299
- @ability.can :read, Article, :priority.lt => 2
300
- article1 = Article.create!(:priority => 1)
301
- article2 = Article.create!(:priority => 3)
302
- expect(Article.accessible_by(@ability)).to eq([article1])
303
- expect(@ability).to be_able_to(:read, article1)
304
- expect(@ability).to_not be_able_to(:read, article2)
305
- end
306
-
307
- it "merges MetaWhere and non-MetaWhere conditions" do
308
- @ability.can :read, Article, :priority.lt => 2
309
- @ability.can :read, Article, :priority => 1
310
- article1 = Article.create!(:priority => 1)
311
- article2 = Article.create!(:priority => 3)
312
- expect(Article.accessible_by(@ability)).to eq([article1])
313
- expect(@ability).to be_able_to(:read, article1)
314
- expect(@ability).to_not be_able_to(:read, article2)
315
- end
316
-
317
- it "matches any MetaWhere condition" do
318
- adapter = CanCan::ModelAdapters::ActiveRecordAdapter
319
- article1 = Article.new(:priority => 1, :name => "Hello World")
320
- expect(adapter.matches_condition?(article1, :priority.eq, 1)).to be_true
321
- expect(adapter.matches_condition?(article1, :priority.eq, 2)).to be_false
322
- expect(adapter.matches_condition?(article1, :priority.eq_any, [1, 2])).to be_true
323
- expect(adapter.matches_condition?(article1, :priority.eq_any, [2, 3])).to be_false
324
- expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 1])).to be_true
325
- expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 2])).to be_false
326
- expect(adapter.matches_condition?(article1, :priority.ne, 2)).to be_true
327
- expect(adapter.matches_condition?(article1, :priority.ne, 1)).to be_false
328
- expect(adapter.matches_condition?(article1, :priority.in, [1, 2])).to be_true
329
- expect(adapter.matches_condition?(article1, :priority.in, [2, 3])).to be_false
330
- expect(adapter.matches_condition?(article1, :priority.nin, [2, 3])).to be_true
331
- expect(adapter.matches_condition?(article1, :priority.nin, [1, 2])).to be_false
332
- expect(adapter.matches_condition?(article1, :priority.lt, 2)).to be_true
333
- expect(adapter.matches_condition?(article1, :priority.lt, 1)).to be_false
334
- expect(adapter.matches_condition?(article1, :priority.lteq, 1)).to be_true
335
- expect(adapter.matches_condition?(article1, :priority.lteq, 0)).to be_false
336
- expect(adapter.matches_condition?(article1, :priority.gt, 0)).to be_true
337
- expect(adapter.matches_condition?(article1, :priority.gt, 1)).to be_false
338
- expect(adapter.matches_condition?(article1, :priority.gteq, 1)).to be_true
339
- expect(adapter.matches_condition?(article1, :priority.gteq, 2)).to be_false
340
- expect(adapter.matches_condition?(article1, :name.like, "%ello worl%")).to be_true
341
- expect(adapter.matches_condition?(article1, :name.like, "hello world")).to be_true
342
- expect(adapter.matches_condition?(article1, :name.like, "hello%")).to be_true
343
- expect(adapter.matches_condition?(article1, :name.like, "h%d")).to be_true
344
- expect(adapter.matches_condition?(article1, :name.like, "%helo%")).to be_false
345
- expect(adapter.matches_condition?(article1, :name.like, "hello")).to be_false
346
- expect(adapter.matches_condition?(article1, :name.like, "hello.world")).to be_false
347
- # For some reason this is reporting "The not_matches MetaWhere condition is not supported."
348
- # expect(adapter.matches_condition?(article1, :name.nlike, "%helo%")).to be_true
349
- # expect(adapter.matches_condition?(article1, :name.nlike, "%ello worl%")).to be_false
350
- end
351
-
352
302
  it 'should not execute a scope when checking ability on the class' do
353
303
  relation = Article.where(:secret => true)
354
304
  @ability.can :read, Article, relation do |article|
@@ -359,5 +309,69 @@ if defined? CanCan::ModelAdapters::ActiveRecordAdapter
359
309
 
360
310
  expect { @ability.can? :read, Article }.not_to raise_error
361
311
  end
312
+
313
+ context "when MetaWhere is defined" do
314
+
315
+ before :each do
316
+ pending "[Deprecated] MetaWhere support is being removed" unless defined? MetaWhere
317
+ end
318
+
319
+ it "restricts articles given a MetaWhere condition" do
320
+ # pending "[Deprecated] MetaWhere support is being removed" unless defined? MetaWhere
321
+ @ability.can :read, Article, :priority.lt => 2
322
+ article1 = Article.create!(:priority => 1)
323
+ article2 = Article.create!(:priority => 3)
324
+ expect(Article.accessible_by(@ability)).to eq([article1])
325
+ expect(@ability).to be_able_to(:read, article1)
326
+ expect(@ability).to_not be_able_to(:read, article2)
327
+ end
328
+
329
+ it "merges MetaWhere and non-MetaWhere conditions" do
330
+ # pending "[Deprecated] MetaWhere support is being removed" unless defined? MetaWhere
331
+ @ability.can :read, Article, :priority.lt => 2
332
+ @ability.can :read, Article, :priority => 1
333
+ article1 = Article.create!(:priority => 1)
334
+ article2 = Article.create!(:priority => 3)
335
+ expect(Article.accessible_by(@ability)).to eq([article1])
336
+ expect(@ability).to be_able_to(:read, article1)
337
+ expect(@ability).to_not be_able_to(:read, article2)
338
+ end
339
+
340
+ it "matches any MetaWhere condition" do
341
+
342
+ adapter = CanCan::ModelAdapters::ActiveRecordAdapter
343
+ article1 = Article.new(:priority => 1, :name => "Hello World")
344
+ expect(adapter.matches_condition?(article1, :priority.eq, 1)).to be_true
345
+ expect(adapter.matches_condition?(article1, :priority.eq, 2)).to be_false
346
+ expect(adapter.matches_condition?(article1, :priority.eq_any, [1, 2])).to be_true
347
+ expect(adapter.matches_condition?(article1, :priority.eq_any, [2, 3])).to be_false
348
+ expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 1])).to be_true
349
+ expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 2])).to be_false
350
+ expect(adapter.matches_condition?(article1, :priority.ne, 2)).to be_true
351
+ expect(adapter.matches_condition?(article1, :priority.ne, 1)).to be_false
352
+ expect(adapter.matches_condition?(article1, :priority.in, [1, 2])).to be_true
353
+ expect(adapter.matches_condition?(article1, :priority.in, [2, 3])).to be_false
354
+ expect(adapter.matches_condition?(article1, :priority.nin, [2, 3])).to be_true
355
+ expect(adapter.matches_condition?(article1, :priority.nin, [1, 2])).to be_false
356
+ expect(adapter.matches_condition?(article1, :priority.lt, 2)).to be_true
357
+ expect(adapter.matches_condition?(article1, :priority.lt, 1)).to be_false
358
+ expect(adapter.matches_condition?(article1, :priority.lteq, 1)).to be_true
359
+ expect(adapter.matches_condition?(article1, :priority.lteq, 0)).to be_false
360
+ expect(adapter.matches_condition?(article1, :priority.gt, 0)).to be_true
361
+ expect(adapter.matches_condition?(article1, :priority.gt, 1)).to be_false
362
+ expect(adapter.matches_condition?(article1, :priority.gteq, 1)).to be_true
363
+ expect(adapter.matches_condition?(article1, :priority.gteq, 2)).to be_false
364
+ expect(adapter.matches_condition?(article1, :name.like, "%ello worl%")).to be_true
365
+ expect(adapter.matches_condition?(article1, :name.like, "hello world")).to be_true
366
+ expect(adapter.matches_condition?(article1, :name.like, "hello%")).to be_true
367
+ expect(adapter.matches_condition?(article1, :name.like, "h%d")).to be_true
368
+ expect(adapter.matches_condition?(article1, :name.like, "%helo%")).to be_false
369
+ expect(adapter.matches_condition?(article1, :name.like, "hello")).to be_false
370
+ expect(adapter.matches_condition?(article1, :name.like, "hello.world")).to be_false
371
+ # For some reason this is reporting "The not_matches MetaWhere condition is not supported."
372
+ # expect(adapter.matches_condition?(article1, :name.nlike, "%helo%")).to be_true
373
+ # expect(adapter.matches_condition?(article1, :name.nlike, "%ello worl%")).to be_false
374
+ end
375
+ end
362
376
  end
363
377
  end
@@ -0,0 +1,148 @@
1
+ if ENV["MODEL_ADAPTER"] == "sequel"
2
+ require "spec_helper"
3
+
4
+ DB = Sequel.sqlite
5
+
6
+ DB.create_table :users do
7
+ primary_key :id
8
+ String :name
9
+ end
10
+
11
+ class User < Sequel::Model
12
+ one_to_many :articles
13
+ end
14
+
15
+ DB.create_table :articles do
16
+ primary_key :id
17
+ String :name
18
+ TrueClass :published
19
+ TrueClass :secret
20
+ Integer :priority
21
+ foreign_key :user_id, :users
22
+ end
23
+
24
+ class Article < Sequel::Model
25
+ many_to_one :user
26
+ one_to_many :comments
27
+ end
28
+
29
+ DB.create_table :comments do
30
+ primary_key :id
31
+ TrueClass :spam
32
+ foreign_key :article_id, :articles
33
+ end
34
+
35
+ class Comment < Sequel::Model
36
+ many_to_one :article
37
+ end
38
+
39
+ describe CanCan::ModelAdapters::SequelAdapter do
40
+ before(:each) do
41
+ Comment.dataset.delete
42
+ Article.dataset.delete
43
+ User.dataset.delete
44
+ @ability = Object.new
45
+ @ability.extend(CanCan::Ability)
46
+ end
47
+
48
+ it "should be for only sequel model classes" do
49
+ CanCan::ModelAdapters::SequelAdapter.should_not be_for_class(Object)
50
+ CanCan::ModelAdapters::SequelAdapter.should be_for_class(Article)
51
+ CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::SequelAdapter
52
+ end
53
+
54
+ it "should find record" do
55
+ article = Article.create
56
+ CanCan::ModelAdapters::SequelAdapter.find(Article, article.id).should == article
57
+ end
58
+
59
+ it "should not fetch any records when no abilities are defined" do
60
+ Article.create
61
+ Article.accessible_by(@ability).all.should be_empty
62
+ end
63
+
64
+ it "should fetch all articles when one can read all" do
65
+ @ability.can :read, Article
66
+ article = Article.create
67
+ @ability.should be_able_to(:read, article)
68
+ Article.accessible_by(@ability).all.should == [article]
69
+ end
70
+
71
+ it "should fetch only the articles that are published" do
72
+ @ability.can :read, Article, :published => true
73
+ article1 = Article.create(:published => true)
74
+ article2 = Article.create(:published => false)
75
+ @ability.should be_able_to(:read, article1)
76
+ @ability.should_not be_able_to(:read, article2)
77
+ Article.accessible_by(@ability).all.should == [article1]
78
+ end
79
+
80
+ it "should fetch any articles which are published or secret" do
81
+ @ability.can :read, Article, :published => true
82
+ @ability.can :read, Article, :secret => true
83
+ article1 = Article.create(:published => true, :secret => false)
84
+ article2 = Article.create(:published => true, :secret => true)
85
+ article3 = Article.create(:published => false, :secret => true)
86
+ article4 = Article.create(:published => false, :secret => false)
87
+ @ability.should be_able_to(:read, article1)
88
+ @ability.should be_able_to(:read, article2)
89
+ @ability.should be_able_to(:read, article3)
90
+ @ability.should_not be_able_to(:read, article4)
91
+ Article.accessible_by(@ability).all.should == [article1, article2, article3]
92
+ end
93
+
94
+ it "should fetch only the articles that are published and not secret" do
95
+ @ability.can :read, Article, :published => true
96
+ @ability.cannot :read, Article, :secret => true
97
+ article1 = Article.create(:published => true, :secret => false)
98
+ article2 = Article.create(:published => true, :secret => true)
99
+ article3 = Article.create(:published => false, :secret => true)
100
+ article4 = Article.create(:published => false, :secret => false)
101
+ @ability.should be_able_to(:read, article1)
102
+ @ability.should_not be_able_to(:read, article2)
103
+ @ability.should_not be_able_to(:read, article3)
104
+ @ability.should_not be_able_to(:read, article4)
105
+ Article.accessible_by(@ability).all.should == [article1]
106
+ end
107
+
108
+ it "should only read comments for articles which are published" do
109
+ @ability.can :read, Comment, :article => { :published => true }
110
+ comment1 = Comment.create(:article => Article.create(:published => true))
111
+ comment2 = Comment.create(:article => Article.create(:published => false))
112
+ @ability.should be_able_to(:read, comment1)
113
+ @ability.should_not be_able_to(:read, comment2)
114
+ Comment.accessible_by(@ability).all.should == [comment1]
115
+ end
116
+
117
+ it "should only read comments for articles which are published and user is 'me'" do
118
+ @ability.can :read, Comment, :article => { :user => { :name => 'me' }, :published => true }
119
+ user1 = User.create(:name => 'me')
120
+ comment1 = Comment.create(:article => Article.create(:published => true, :user => user1))
121
+ comment2 = Comment.create(:article => Article.create(:published => true))
122
+ comment3 = Comment.create(:article => Article.create(:published => false, :user => user1))
123
+ @ability.should be_able_to(:read, comment1)
124
+ @ability.should_not be_able_to(:read, comment2)
125
+ @ability.should_not be_able_to(:read, comment3)
126
+ Comment.accessible_by(@ability).all.should == [comment1]
127
+ end
128
+
129
+ it "should allow conditions in SQL and merge with hash conditions" do
130
+ @ability.can :read, Article, :published => true
131
+ @ability.can :read, Article, ["secret=?", true] do |article|
132
+ article.secret
133
+ end
134
+ @ability.cannot :read, Article, "priority > 1" do |article|
135
+ article.priority > 1
136
+ end
137
+ article1 = Article.create(:published => true, :secret => false, :priority => 1)
138
+ article2 = Article.create(:published => true, :secret => true, :priority => 1)
139
+ article3 = Article.create(:published => true, :secret => true, :priority => 2)
140
+ article4 = Article.create(:published => false, :secret => false, :priority => 2)
141
+ @ability.should be_able_to(:read, article1)
142
+ @ability.should be_able_to(:read, article2)
143
+ @ability.should_not be_able_to(:read, article3)
144
+ @ability.should_not be_able_to(:read, article4)
145
+ Article.accessible_by(@ability).all.should == [article1, article2]
146
+ end
147
+ end
148
+ end