cancancan 1.13.1 → 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 (73) 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 +93 -194
  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 +38 -41
  11. data/lib/cancan/controller_resource.rb +52 -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 -13
  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 -105
  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 -56
  37. data/.gitignore +0 -15
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -28
  40. data/Appraisals +0 -81
  41. data/CHANGELOG.rdoc +0 -518
  42. data/CONTRIBUTING.md +0 -23
  43. data/Gemfile +0 -3
  44. data/LICENSE +0 -22
  45. data/README.md +0 -214
  46. data/Rakefile +0 -9
  47. data/gemfiles/activerecord_3.2.gemfile +0 -16
  48. data/gemfiles/activerecord_4.0.gemfile +0 -17
  49. data/gemfiles/activerecord_4.1.gemfile +0 -17
  50. data/gemfiles/activerecord_4.2.gemfile +0 -18
  51. data/gemfiles/mongoid_2.x.gemfile +0 -16
  52. data/gemfiles/sequel_3.x.gemfile +0 -16
  53. data/lib/cancan/inherited_resource.rb +0 -20
  54. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
  55. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  56. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  57. data/spec/README.rdoc +0 -27
  58. data/spec/cancan/ability_spec.rb +0 -521
  59. data/spec/cancan/controller_additions_spec.rb +0 -141
  60. data/spec/cancan/controller_resource_spec.rb +0 -632
  61. data/spec/cancan/exceptions_spec.rb +0 -58
  62. data/spec/cancan/inherited_resource_spec.rb +0 -71
  63. data/spec/cancan/matchers_spec.rb +0 -29
  64. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
  65. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -384
  66. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  67. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  68. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  69. data/spec/cancan/rule_spec.rb +0 -52
  70. data/spec/matchers.rb +0 -13
  71. data/spec/spec.opts +0 -2
  72. data/spec/spec_helper.rb +0 -27
  73. 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,227 +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
- end
16
-
17
- Mongoid.configure do |config|
18
- config.master = Mongo::Connection.new('127.0.0.1', 27017).db("cancan_mongoid_spec")
19
- end
20
-
21
- describe CanCan::ModelAdapters::MongoidAdapter do
22
- context "Mongoid defined" do
23
- before(:each) do
24
- (@ability = double).extend(CanCan::Ability)
25
- end
26
-
27
- after(:each) do
28
- Mongoid.master.collections.select do |collection|
29
- collection.name !~ /system/
30
- end.each(&:drop)
31
- end
32
-
33
- it "is for only Mongoid classes" do
34
- expect(CanCan::ModelAdapters::MongoidAdapter).not_to be_for_class(Object)
35
- expect(CanCan::ModelAdapters::MongoidAdapter).to be_for_class(MongoidProject)
36
- expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject)).to eq(CanCan::ModelAdapters::MongoidAdapter)
37
- end
38
-
39
- it "finds record" do
40
- project = MongoidProject.create
41
- expect(CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id)).to eq(project)
42
- end
43
-
44
- it "compares properties on mongoid documents with the conditions hash" do
45
- model = MongoidProject.new
46
- @ability.can :read, MongoidProject, :id => model.id
47
- expect(@ability).to be_able_to(:read, model)
48
- end
49
-
50
- it "is 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
- expect(@ability).to be_able_to(:foo, one_to_three)
56
- expect(@ability).not_to be_able_to(:foo, two_to_five)
57
- end
58
-
59
- it "returns [] when no ability is defined so no records are found" do
60
- MongoidProject.create(:title => 'Sir')
61
- MongoidProject.create(:title => 'Lord')
62
- MongoidProject.create(:title => 'Dude')
63
-
64
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([])
65
- end
66
-
67
- it "returns the correct records based on the defined ability" do
68
- @ability.can :read, MongoidProject, :title => "Sir"
69
- sir = MongoidProject.create(:title => 'Sir')
70
- lord = MongoidProject.create(:title => 'Lord')
71
- dude = MongoidProject.create(:title => 'Dude')
72
-
73
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir])
74
- end
75
-
76
- it "returns 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
- expect(MongoidProject.accessible_by(@ability, :destroy).entries).to eq([sir])
85
- end
86
-
87
- it "is 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
- expect(MongoidProject.accessible_by(@ability, :read).count).to eq(2)
94
- end
95
-
96
- it "returns everything when the defined ability is access all" do
97
- @ability.can :manage, :all
98
- sir = MongoidProject.create(:title => 'Sir')
99
- lord = MongoidProject.create(:title => 'Lord')
100
- dude = MongoidProject.create(:title => 'Dude')
101
-
102
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir, lord, dude])
103
- end
104
-
105
- it "allows 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
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir])
112
- end
113
-
114
- describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
115
- it "handles :field.in" do
116
- obj = MongoidProject.create(:title => 'Sir')
117
- @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"]
118
- expect(@ability.can?(:read, obj)).to eq(true)
119
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
120
-
121
- obj2 = MongoidProject.create(:title => 'Lord')
122
- expect(@ability.can?(:read, obj2)).to be(false)
123
- end
124
-
125
- describe "activates only when there are Criteria in the hash" do
126
- it "Calls where on the model class when there are criteria" do
127
- obj = MongoidProject.create(:title => 'Bird')
128
- @conditions = {:title.nin => ["Fork", "Spoon"]}
129
-
130
- @ability.can :read, MongoidProject, @conditions
131
- expect(@ability).to be_able_to(:read, obj)
132
- end
133
- it "Calls the base version if there are no mongoid criteria" do
134
- obj = MongoidProject.new(:title => 'Bird')
135
- @conditions = {:id => obj.id}
136
- @ability.can :read, MongoidProject, @conditions
137
- expect(@ability).to be_able_to(:read, obj)
138
- end
139
- end
140
-
141
- it "handles :field.nin" do
142
- obj = MongoidProject.create(:title => 'Sir')
143
- @ability.can :read, MongoidProject, :title.nin => ["Lord", "Madam"]
144
- expect(@ability.can?(:read, obj)).to eq(true)
145
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
146
-
147
- obj2 = MongoidProject.create(:title => 'Lord')
148
- expect(@ability.can?(:read, obj2)).to be(false)
149
- end
150
-
151
- it "handles :field.size" do
152
- obj = MongoidProject.create(:titles => ['Palatin', 'Margrave'])
153
- @ability.can :read, MongoidProject, :titles.size => 2
154
- expect(@ability.can?(:read, obj)).to eq(true)
155
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
156
-
157
- obj2 = MongoidProject.create(:titles => ['Palatin', 'Margrave', 'Marquis'])
158
- expect(@ability.can?(:read, obj2)).to be(false)
159
- end
160
-
161
- it "handles :field.exists" do
162
- obj = MongoidProject.create(:titles => ['Palatin', 'Margrave'])
163
- @ability.can :read, MongoidProject, :titles.exists => true
164
- expect(@ability.can?(:read, obj)).to eq(true)
165
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
166
-
167
- obj2 = MongoidProject.create
168
- expect(@ability.can?(:read, obj2)).to be(false)
169
- end
170
-
171
- it "handles :field.gt" do
172
- obj = MongoidProject.create(:age => 50)
173
- @ability.can :read, MongoidProject, :age.gt => 45
174
- expect(@ability.can?(:read, obj)).to eq(true)
175
- expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
176
-
177
- obj2 = MongoidProject.create(:age => 40)
178
- expect(@ability.can?(:read, obj2)).to be(false)
179
- end
180
-
181
- it "handles instance not saved to database" do
182
- obj = MongoidProject.new(:title => 'Sir')
183
- @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"]
184
- expect(@ability.can?(:read, obj)).to eq(true)
185
-
186
- # accessible_by only returns saved records
187
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([])
188
-
189
- obj2 = MongoidProject.new(:title => 'Lord')
190
- expect(@ability.can?(:read, obj2)).to be(false)
191
- end
192
- end
193
-
194
- it "calls where with matching ability conditions" do
195
- obj = MongoidProject.create(:foo => {:bar => 1})
196
- @ability.can :read, MongoidProject, :foo => {:bar => 1}
197
- expect(MongoidProject.accessible_by(@ability, :read).entries.first).to eq(obj)
198
- end
199
-
200
- it "excludes from the result if set to cannot" do
201
- obj = MongoidProject.create(:bar => 1)
202
- obj2 = MongoidProject.create(:bar => 2)
203
- @ability.can :read, MongoidProject
204
- @ability.cannot :read, MongoidProject, :bar => 2
205
- expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([obj])
206
- end
207
-
208
- it "combines the rules" do
209
- obj = MongoidProject.create(:bar => 1)
210
- obj2 = MongoidProject.create(:bar => 2)
211
- obj3 = MongoidProject.create(:bar => 3)
212
- @ability.can :read, MongoidProject, :bar => 1
213
- @ability.can :read, MongoidProject, :bar => 2
214
- expect(MongoidProject.accessible_by(@ability, :read).entries).to match_array([obj, obj2])
215
- end
216
-
217
- it "does not allow to fetch records when ability with just block present" do
218
- @ability.can :read, MongoidProject do
219
- false
220
- end
221
- expect {
222
- MongoidProject.accessible_by(@ability)
223
- }.to raise_error(CanCan::Error)
224
- end
225
- end
226
- end
227
- 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
@@ -1,2 +0,0 @@
1
- --color
2
- --backtrace
@@ -1,27 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
-
4
- Bundler.require
5
-
6
- require 'matchers'
7
- require 'cancan/matchers'
8
-
9
- # I8n setting to fix deprecation.
10
- if defined?(I18n) && I18n.respond_to?('enforce_available_locales=')
11
- I18n.enforce_available_locales = false
12
- end
13
-
14
- # Add support to load paths
15
- $:.unshift File.expand_path('../support', __FILE__)
16
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
17
-
18
- RSpec.configure do |config|
19
- config.filter_run :focus => true
20
- config.run_all_when_everything_filtered = true
21
- config.mock_with :rspec
22
- config.order = 'random'
23
-
24
- config.expect_with :rspec do |c|
25
- c.syntax = :expect
26
- end
27
- end