cancancan 1.15.0 → 3.1.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.
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