cancancan 1.15.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +18 -18
  3. data/init.rb +2 -0
  4. data/lib/cancan.rb +9 -11
  5. data/lib/cancan/ability.rb +90 -203
  6. data/lib/cancan/ability/actions.rb +93 -0
  7. data/lib/cancan/ability/rules.rb +93 -0
  8. data/lib/cancan/ability/strong_parameter_support.rb +41 -0
  9. data/lib/cancan/conditions_matcher.rb +106 -0
  10. data/lib/cancan/controller_additions.rb +29 -36
  11. data/lib/cancan/controller_resource.rb +46 -211
  12. data/lib/cancan/controller_resource_builder.rb +26 -0
  13. data/lib/cancan/controller_resource_finder.rb +42 -0
  14. data/lib/cancan/controller_resource_loader.rb +120 -0
  15. data/lib/cancan/controller_resource_name_finder.rb +23 -0
  16. data/lib/cancan/controller_resource_sanitizer.rb +32 -0
  17. data/lib/cancan/exceptions.rb +17 -5
  18. data/lib/cancan/matchers.rb +12 -3
  19. data/lib/cancan/model_adapters/abstract_adapter.rb +10 -8
  20. data/lib/cancan/model_adapters/active_record_4_adapter.rb +39 -43
  21. data/lib/cancan/model_adapters/active_record_5_adapter.rb +68 -0
  22. data/lib/cancan/model_adapters/active_record_adapter.rb +77 -82
  23. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  24. data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  25. data/lib/cancan/model_adapters/default_adapter.rb +2 -0
  26. data/lib/cancan/model_additions.rb +2 -1
  27. data/lib/cancan/parameter_validators.rb +9 -0
  28. data/lib/cancan/relevant.rb +29 -0
  29. data/lib/cancan/rule.rb +76 -106
  30. data/lib/cancan/rules_compressor.rb +23 -0
  31. data/lib/cancan/unauthorized_message_resolver.rb +24 -0
  32. data/lib/cancan/version.rb +3 -1
  33. data/lib/cancancan.rb +2 -0
  34. data/lib/generators/cancan/ability/ability_generator.rb +4 -2
  35. data/lib/generators/cancan/ability/templates/ability.rb +2 -0
  36. metadata +66 -57
  37. data/.gitignore +0 -15
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -33
  40. data/Appraisals +0 -104
  41. data/CHANGELOG.rdoc +0 -527
  42. data/CONTRIBUTING.md +0 -23
  43. data/Gemfile +0 -3
  44. data/LICENSE +0 -22
  45. data/README.md +0 -217
  46. data/Rakefile +0 -9
  47. data/gemfiles/activerecord_3.2.gemfile +0 -17
  48. data/gemfiles/activerecord_4.0.gemfile +0 -18
  49. data/gemfiles/activerecord_4.1.gemfile +0 -18
  50. data/gemfiles/activerecord_4.2.gemfile +0 -19
  51. data/gemfiles/activerecord_5.0.gemfile +0 -19
  52. data/gemfiles/mongoid_2.x.gemfile +0 -17
  53. data/gemfiles/sequel_3.x.gemfile +0 -17
  54. data/lib/cancan/inherited_resource.rb +0 -20
  55. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
  56. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -75
  57. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  58. data/spec/README.rdoc +0 -27
  59. data/spec/cancan/ability_spec.rb +0 -544
  60. data/spec/cancan/controller_additions_spec.rb +0 -151
  61. data/spec/cancan/controller_resource_spec.rb +0 -643
  62. data/spec/cancan/exceptions_spec.rb +0 -58
  63. data/spec/cancan/inherited_resource_spec.rb +0 -71
  64. data/spec/cancan/matchers_spec.rb +0 -29
  65. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -154
  66. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -405
  67. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  68. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -247
  69. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  70. data/spec/cancan/rule_spec.rb +0 -52
  71. data/spec/matchers.rb +0 -13
  72. data/spec/spec.opts +0 -2
  73. data/spec/spec_helper.rb +0 -27
  74. data/spec/support/ability.rb +0 -7
@@ -1,7 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe CanCan::ModelAdapters::DefaultAdapter do
4
- it "is default for generic classes" do
5
- expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Object)).to eq(CanCan::ModelAdapters::DefaultAdapter)
6
- end
7
- end
@@ -1,247 +0,0 @@
1
- require "spec_helper"
2
-
3
- if defined? CanCan::ModelAdapters::MongoidAdapter
4
-
5
- class MongoidCategory
6
- include Mongoid::Document
7
-
8
- references_many :mongoid_projects
9
- end
10
-
11
- class MongoidProject
12
- include Mongoid::Document
13
-
14
- referenced_in :mongoid_category
15
- references_many :mongoid_sub_projects
16
- end
17
-
18
- class MongoidSubProject
19
- include Mongoid::Document
20
-
21
- referenced_in :mongoid_project
22
- end
23
-
24
- Mongoid.configure do |config|
25
- config.master = Mongo::Connection.new('127.0.0.1', 27017).db("cancan_mongoid_spec")
26
- end
27
-
28
- describe CanCan::ModelAdapters::MongoidAdapter do
29
- context "Mongoid defined" do
30
- before(:each) do
31
- (@ability = double).extend(CanCan::Ability)
32
- end
33
-
34
- after(:each) do
35
- Mongoid.master.collections.select do |collection|
36
- collection.name !~ /system/
37
- end.each(&:drop)
38
- end
39
-
40
- it "is for only Mongoid classes" do
41
- expect(CanCan::ModelAdapters::MongoidAdapter).not_to be_for_class(Object)
42
- expect(CanCan::ModelAdapters::MongoidAdapter).to be_for_class(MongoidProject)
43
- expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject)).to eq(CanCan::ModelAdapters::MongoidAdapter)
44
- end
45
-
46
- it "finds record" do
47
- project = MongoidProject.create
48
- expect(CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id)).to eq(project)
49
- end
50
-
51
- it "compares properties on mongoid documents with the conditions hash" do
52
- model = MongoidProject.new
53
- @ability.can :read, MongoidProject, :id => model.id
54
- expect(@ability).to be_able_to(:read, model)
55
- end
56
-
57
- it "is able to read hashes when field is array" do
58
- one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three'])
59
- two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five'])
60
-
61
- @ability.can :foo, MongoidProject, :numbers => 'one'
62
- expect(@ability).to be_able_to(:foo, one_to_three)
63
- expect(@ability).not_to be_able_to(:foo, two_to_five)
64
- end
65
-
66
- it "returns [] when no ability is defined so no records are found" do
67
- MongoidProject.create(:title => 'Sir')
68
- MongoidProject.create(:title => 'Lord')
69
- MongoidProject.create(:title => 'Dude')
70
-
71
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([])
72
- end
73
-
74
- it "returns the correct records based on the defined ability" do
75
- @ability.can :read, MongoidProject, :title => "Sir"
76
- sir = MongoidProject.create(:title => 'Sir')
77
- lord = MongoidProject.create(:title => 'Lord')
78
- dude = MongoidProject.create(:title => 'Dude')
79
-
80
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir])
81
- end
82
-
83
- it "returns the correct records when a mix of can and cannot rules in defined ability" do
84
- @ability.can :manage, MongoidProject, :title => 'Sir'
85
- @ability.cannot :destroy, MongoidProject
86
-
87
- sir = MongoidProject.create(:title => 'Sir')
88
- lord = MongoidProject.create(:title => 'Lord')
89
- dude = MongoidProject.create(:title => 'Dude')
90
-
91
- expect(MongoidProject.accessible_by(@ability, :destroy).entries).to eq([sir])
92
- end
93
-
94
- it "is able to mix empty conditions and hashes" do
95
- @ability.can :read, MongoidProject
96
- @ability.can :read, MongoidProject, :title => 'Sir'
97
- sir = MongoidProject.create(:title => 'Sir')
98
- lord = MongoidProject.create(:title => 'Lord')
99
-
100
- expect(MongoidProject.accessible_by(@ability, :read).count).to eq(2)
101
- end
102
-
103
- it "returns everything when the defined ability is access all" do
104
- @ability.can :manage, :all
105
- sir = MongoidProject.create(:title => 'Sir')
106
- lord = MongoidProject.create(:title => 'Lord')
107
- dude = MongoidProject.create(:title => 'Dude')
108
-
109
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir, lord, dude])
110
- end
111
-
112
- it "allows a scope for conditions" do
113
- @ability.can :read, MongoidProject, MongoidProject.where(:title => 'Sir')
114
- sir = MongoidProject.create(:title => 'Sir')
115
- lord = MongoidProject.create(:title => 'Lord')
116
- dude = MongoidProject.create(:title => 'Dude')
117
-
118
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir])
119
- end
120
-
121
- describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
122
- it "handles :field.in" do
123
- obj = MongoidProject.create(:title => 'Sir')
124
- @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"]
125
- expect(@ability.can?(:read, obj)).to eq(true)
126
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
127
-
128
- obj2 = MongoidProject.create(:title => 'Lord')
129
- expect(@ability.can?(:read, obj2)).to be(false)
130
- end
131
-
132
- describe "activates only when there are Criteria in the hash" do
133
- it "Calls where on the model class when there are criteria" do
134
- obj = MongoidProject.create(:title => 'Bird')
135
- @conditions = {:title.nin => ["Fork", "Spoon"]}
136
-
137
- @ability.can :read, MongoidProject, @conditions
138
- expect(@ability).to be_able_to(:read, obj)
139
- end
140
- it "Calls the base version if there are no mongoid criteria" do
141
- obj = MongoidProject.new(:title => 'Bird')
142
- @conditions = {:id => obj.id}
143
- @ability.can :read, MongoidProject, @conditions
144
- expect(@ability).to be_able_to(:read, obj)
145
- end
146
- end
147
-
148
- it "handles :field.nin" do
149
- obj = MongoidProject.create(:title => 'Sir')
150
- @ability.can :read, MongoidProject, :title.nin => ["Lord", "Madam"]
151
- expect(@ability.can?(:read, obj)).to eq(true)
152
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
153
-
154
- obj2 = MongoidProject.create(:title => 'Lord')
155
- expect(@ability.can?(:read, obj2)).to be(false)
156
- end
157
-
158
- it "handles :field.size" do
159
- obj = MongoidProject.create(:titles => ['Palatin', 'Margrave'])
160
- @ability.can :read, MongoidProject, :titles.size => 2
161
- expect(@ability.can?(:read, obj)).to eq(true)
162
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
163
-
164
- obj2 = MongoidProject.create(:titles => ['Palatin', 'Margrave', 'Marquis'])
165
- expect(@ability.can?(:read, obj2)).to be(false)
166
- end
167
-
168
- it "handles :field.exists" do
169
- obj = MongoidProject.create(:titles => ['Palatin', 'Margrave'])
170
- @ability.can :read, MongoidProject, :titles.exists => true
171
- expect(@ability.can?(:read, obj)).to eq(true)
172
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
173
-
174
- obj2 = MongoidProject.create
175
- expect(@ability.can?(:read, obj2)).to be(false)
176
- end
177
-
178
- it "handles :field.gt" do
179
- obj = MongoidProject.create(:age => 50)
180
- @ability.can :read, MongoidProject, :age.gt => 45
181
- expect(@ability.can?(:read, obj)).to eq(true)
182
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
183
-
184
- obj2 = MongoidProject.create(:age => 40)
185
- expect(@ability.can?(:read, obj2)).to be(false)
186
- end
187
-
188
- it "handles instance not saved to database" do
189
- obj = MongoidProject.new(:title => 'Sir')
190
- @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"]
191
- expect(@ability.can?(:read, obj)).to eq(true)
192
-
193
- # accessible_by only returns saved records
194
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([])
195
-
196
- obj2 = MongoidProject.new(:title => 'Lord')
197
- expect(@ability.can?(:read, obj2)).to be(false)
198
- end
199
- end
200
-
201
- it "calls where with matching ability conditions" do
202
- obj = MongoidProject.create(:foo => {:bar => 1})
203
- @ability.can :read, MongoidProject, :foo => {:bar => 1}
204
- expect(MongoidProject.accessible_by(@ability, :read).entries.first).to eq(obj)
205
- end
206
-
207
- it "excludes from the result if set to cannot" do
208
- obj = MongoidProject.create(:bar => 1)
209
- obj2 = MongoidProject.create(:bar => 2)
210
- @ability.can :read, MongoidProject
211
- @ability.cannot :read, MongoidProject, :bar => 2
212
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([obj])
213
- end
214
-
215
- it "combines the rules" do
216
- obj = MongoidProject.create(:bar => 1)
217
- obj2 = MongoidProject.create(:bar => 2)
218
- obj3 = MongoidProject.create(:bar => 3)
219
- @ability.can :read, MongoidProject, :bar => 1
220
- @ability.can :read, MongoidProject, :bar => 2
221
- expect(MongoidProject.accessible_by(@ability, :read).entries).to match_array([obj, obj2])
222
- end
223
-
224
- it "does not allow to fetch records when ability with just block present" do
225
- @ability.can :read, MongoidProject do
226
- false
227
- end
228
- expect {
229
- MongoidProject.accessible_by(@ability)
230
- }.to raise_error(CanCan::Error)
231
- end
232
-
233
- it "can handle nested queries for accessible_by" do
234
- @ability.can :read, MongoidSubProject, {:mongoid_project => {:mongoid_category => { :name => 'Authorization'}}}
235
- cat1 = MongoidCategory.create name: 'Authentication'
236
- cat2 = MongoidCategory.create name: 'Authorization'
237
- proj1 = cat1.mongoid_projects.create name: 'Proj1'
238
- proj2 = cat2.mongoid_projects.create name: 'Proj2'
239
- sub1 = proj1.mongoid_sub_projects.create name: 'Sub1'
240
- sub2 = proj2.mongoid_sub_projects.create name: 'Sub2'
241
- expect(MongoidSubProject.accessible_by(@ability)).to match_array([sub1])
242
- end
243
-
244
-
245
- end
246
- end
247
- end
@@ -1,132 +0,0 @@
1
- require "spec_helper"
2
-
3
- if defined? CanCan::ModelAdapters::SequelAdapter
4
-
5
- describe CanCan::ModelAdapters::SequelAdapter do
6
- DB = if RUBY_PLATFORM == 'java'
7
- Sequel.connect('jdbc:sqlite:db.sqlite3')
8
- else
9
- Sequel.sqlite
10
- end
11
-
12
- DB.create_table :users do
13
- primary_key :id
14
- String :name
15
- end
16
-
17
- class User < Sequel::Model
18
- one_to_many :articles
19
- end
20
-
21
- DB.create_table :articles do
22
- primary_key :id
23
- String :name
24
- TrueClass :published
25
- TrueClass :secret
26
- Integer :priority
27
- foreign_key :user_id, :users
28
- end
29
-
30
- class Article < Sequel::Model
31
- many_to_one :user
32
- one_to_many :comments
33
- end
34
-
35
- DB.create_table :comments do
36
- primary_key :id
37
- TrueClass :spam
38
- foreign_key :article_id, :articles
39
- end
40
-
41
- class Comment < Sequel::Model
42
- many_to_one :article
43
- end
44
-
45
- before(:each) do
46
- Comment.dataset.delete
47
- Article.dataset.delete
48
- User.dataset.delete
49
- (@ability = double).extend(CanCan::Ability)
50
- end
51
-
52
- it "should be for only sequel model classes" do
53
- expect(CanCan::ModelAdapters::SequelAdapter).to_not be_for_class(Object)
54
- expect(CanCan::ModelAdapters::SequelAdapter).to be_for_class(Article)
55
- expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq CanCan::ModelAdapters::SequelAdapter
56
- end
57
-
58
- it "should find record" do
59
- article = Article.create
60
- expect(CanCan::ModelAdapters::SequelAdapter.find(Article, article.id)).to eq article
61
- end
62
-
63
- it "should not fetch any records when no abilities are defined" do
64
- Article.create
65
- expect(Article.accessible_by(@ability).all).to be_empty
66
- end
67
-
68
- it "should fetch all articles when one can read all" do
69
- @ability.can :read, Article
70
- article = Article.create
71
- expect(Article.accessible_by(@ability).all).to eq [article]
72
- end
73
-
74
- it "should fetch only the articles that are published" do
75
- @ability.can :read, Article, :published => true
76
- article1 = Article.create(:published => true)
77
- article2 = Article.create(:published => false)
78
- expect(Article.accessible_by(@ability).all).to eq [article1]
79
- end
80
-
81
- it "should fetch any articles which are published or secret" do
82
- @ability.can :read, Article, :published => true
83
- @ability.can :read, Article, :secret => true
84
- article1 = Article.create(:published => true, :secret => false)
85
- article2 = Article.create(:published => true, :secret => true)
86
- article3 = Article.create(:published => false, :secret => true)
87
- article4 = Article.create(:published => false, :secret => false)
88
- expect(Article.accessible_by(@ability).all).to eq([article1, article2, article3])
89
- end
90
-
91
- it "should fetch only the articles that are published and not secret" do
92
- @ability.can :read, Article, :published => true
93
- @ability.cannot :read, Article, :secret => true
94
- article1 = Article.create(:published => true, :secret => false)
95
- article2 = Article.create(:published => true, :secret => true)
96
- article3 = Article.create(:published => false, :secret => true)
97
- article4 = Article.create(:published => false, :secret => false)
98
- expect(Article.accessible_by(@ability).all).to eq [article1]
99
- end
100
-
101
- it "should only read comments for articles which are published" do
102
- @ability.can :read, Comment, :article => { :published => true }
103
- comment1 = Comment.create(:article => Article.create(:published => true))
104
- comment2 = Comment.create(:article => Article.create(:published => false))
105
- expect(Comment.accessible_by(@ability).all).to eq [comment1]
106
- end
107
-
108
- it "should only read comments for articles which are published and user is 'me'" do
109
- @ability.can :read, Comment, :article => { :user => { :name => 'me' }, :published => true }
110
- user1 = User.create(:name => 'me')
111
- comment1 = Comment.create(:article => Article.create(:published => true, :user => user1))
112
- comment2 = Comment.create(:article => Article.create(:published => true))
113
- comment3 = Comment.create(:article => Article.create(:published => false, :user => user1))
114
- expect(Comment.accessible_by(@ability).all).to eq [comment1]
115
- end
116
-
117
- it "should allow conditions in SQL and merge with hash conditions" do
118
- @ability.can :read, Article, :published => true
119
- @ability.can :read, Article, ["secret=?", true] do |article|
120
- article.secret
121
- end
122
- @ability.cannot :read, Article, "priority > 1" do |article|
123
- article.priority > 1
124
- end
125
- article1 = Article.create(:published => true, :secret => false, :priority => 1)
126
- article2 = Article.create(:published => true, :secret => true, :priority => 1)
127
- article3 = Article.create(:published => true, :secret => true, :priority => 2)
128
- article4 = Article.create(:published => false, :secret => false, :priority => 2)
129
- expect(Article.accessible_by(@ability).all).to eq [article1, article2]
130
- end
131
- end
132
- end
@@ -1,52 +0,0 @@
1
- require "spec_helper"
2
- require "ostruct" # for OpenStruct below
3
-
4
- # Most of Rule functionality is tested in Ability specs
5
- describe CanCan::Rule do
6
- before(:each) do
7
- @conditions = {}
8
- @rule = CanCan::Rule.new(true, :read, Integer, @conditions, nil)
9
- end
10
-
11
- it "returns no association joins if none exist" do
12
- expect(@rule.associations_hash).to eq({})
13
- end
14
-
15
- it "returns no association for joins if just attributes" do
16
- @conditions[:foo] = :bar
17
- expect(@rule.associations_hash).to eq({})
18
- end
19
-
20
- it "returns single association for joins" do
21
- @conditions[:foo] = {:bar => 1}
22
- expect(@rule.associations_hash).to eq({:foo => {}})
23
- end
24
-
25
- it "returns multiple associations for joins" do
26
- @conditions[:foo] = {:bar => 1}
27
- @conditions[:test] = {1 => 2}
28
- expect(@rule.associations_hash).to eq({:foo => {}, :test => {}})
29
- end
30
-
31
- it "returns nested associations for joins" do
32
- @conditions[:foo] = {:bar => {1 => 2}}
33
- expect(@rule.associations_hash).to eq({:foo => {:bar => {}}})
34
- end
35
-
36
- it "returns no association joins if conditions is nil" do
37
- rule = CanCan::Rule.new(true, :read, Integer, nil, nil)
38
- expect(rule.associations_hash).to eq({})
39
- end
40
-
41
- it "is not mergeable if conditions are not simple hashes" do
42
- meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test')
43
- @conditions[meta_where] = :bar
44
-
45
- expect(@rule).to be_unmergeable
46
- end
47
-
48
- it "is not mergeable if conditions is an empty hash" do
49
- @conditions = {}
50
- expect(@rule).to_not be_unmergeable
51
- end
52
- end
@@ -1,13 +0,0 @@
1
- RSpec::Matchers.define :orderlessly_match do |original_string|
2
- match do |given_string|
3
- original_string.split('').sort == given_string.split('').sort
4
- end
5
-
6
- failure_message do |given_string|
7
- "expected \"#{given_string}\" to have the same characters as \"#{original_string}\""
8
- end
9
-
10
- failure_message_when_negated do |given_string|
11
- "expected \"#{given_string}\" not to have the same characters as \"#{original_string}\""
12
- end
13
- end