cancancan 1.7.1 → 1.8.0

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.
@@ -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