cancancan 1.10.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +19 -21
  3. data/init.rb +2 -0
  4. data/lib/cancan/ability/actions.rb +93 -0
  5. data/lib/cancan/ability/rules.rb +96 -0
  6. data/lib/cancan/ability/strong_parameter_support.rb +41 -0
  7. data/lib/cancan/ability.rb +114 -146
  8. data/lib/cancan/class_matcher.rb +30 -0
  9. data/lib/cancan/conditions_matcher.rb +147 -0
  10. data/lib/cancan/config.rb +101 -0
  11. data/lib/cancan/controller_additions.rb +38 -41
  12. data/lib/cancan/controller_resource.rb +59 -215
  13. data/lib/cancan/controller_resource_builder.rb +26 -0
  14. data/lib/cancan/controller_resource_finder.rb +42 -0
  15. data/lib/cancan/controller_resource_loader.rb +120 -0
  16. data/lib/cancan/controller_resource_name_finder.rb +23 -0
  17. data/lib/cancan/controller_resource_sanitizer.rb +32 -0
  18. data/lib/cancan/exceptions.rb +25 -5
  19. data/lib/cancan/matchers.rb +17 -3
  20. data/lib/cancan/model_adapters/abstract_adapter.rb +30 -9
  21. data/lib/cancan/model_adapters/active_record_4_adapter.rb +43 -15
  22. data/lib/cancan/model_adapters/active_record_5_adapter.rb +61 -0
  23. data/lib/cancan/model_adapters/active_record_adapter.rb +157 -82
  24. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  25. data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  26. data/lib/cancan/model_adapters/default_adapter.rb +2 -0
  27. data/lib/cancan/model_adapters/sti_normalizer.rb +47 -0
  28. data/lib/cancan/model_adapters/strategies/base.rb +40 -0
  29. data/lib/cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery.rb +93 -0
  30. data/lib/cancan/model_adapters/strategies/joined_alias_exists_subquery.rb +31 -0
  31. data/lib/cancan/model_adapters/strategies/left_join.rb +11 -0
  32. data/lib/cancan/model_adapters/strategies/subquery.rb +18 -0
  33. data/lib/cancan/model_additions.rb +6 -3
  34. data/lib/cancan/parameter_validators.rb +9 -0
  35. data/lib/cancan/relevant.rb +29 -0
  36. data/lib/cancan/rule.rb +79 -91
  37. data/lib/cancan/rules_compressor.rb +23 -0
  38. data/lib/cancan/sti_detector.rb +12 -0
  39. data/lib/cancan/unauthorized_message_resolver.rb +24 -0
  40. data/lib/cancan/version.rb +3 -1
  41. data/lib/cancan.rb +16 -12
  42. data/lib/cancancan.rb +2 -0
  43. data/lib/generators/cancan/ability/ability_generator.rb +4 -2
  44. data/lib/generators/cancan/ability/templates/ability.rb +9 -9
  45. metadata +82 -93
  46. data/.gitignore +0 -15
  47. data/.rspec +0 -1
  48. data/.travis.yml +0 -48
  49. data/Appraisals +0 -135
  50. data/CHANGELOG.rdoc +0 -495
  51. data/CONTRIBUTING.md +0 -23
  52. data/Gemfile +0 -3
  53. data/LICENSE +0 -22
  54. data/README.md +0 -197
  55. data/Rakefile +0 -9
  56. data/gemfiles/activerecord_3.0.gemfile +0 -18
  57. data/gemfiles/activerecord_3.1.gemfile +0 -20
  58. data/gemfiles/activerecord_3.2.gemfile +0 -20
  59. data/gemfiles/activerecord_4.0.gemfile +0 -17
  60. data/gemfiles/activerecord_4.1.gemfile +0 -17
  61. data/gemfiles/activerecord_4.2.gemfile +0 -17
  62. data/gemfiles/datamapper_1.x.gemfile +0 -14
  63. data/gemfiles/mongoid_2.x.gemfile +0 -20
  64. data/gemfiles/sequel_3.x.gemfile +0 -20
  65. data/lib/cancan/inherited_resource.rb +0 -20
  66. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -47
  67. data/lib/cancan/model_adapters/data_mapper_adapter.rb +0 -34
  68. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  69. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  70. data/spec/README.rdoc +0 -27
  71. data/spec/cancan/ability_spec.rb +0 -487
  72. data/spec/cancan/controller_additions_spec.rb +0 -141
  73. data/spec/cancan/controller_resource_spec.rb +0 -648
  74. data/spec/cancan/exceptions_spec.rb +0 -58
  75. data/spec/cancan/inherited_resource_spec.rb +0 -71
  76. data/spec/cancan/matchers_spec.rb +0 -29
  77. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -40
  78. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -446
  79. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +0 -119
  80. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  81. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  82. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  83. data/spec/cancan/rule_spec.rb +0 -52
  84. data/spec/matchers.rb +0 -13
  85. data/spec/spec.opts +0 -2
  86. data/spec/spec_helper.rb +0 -27
  87. data/spec/support/ability.rb +0 -7
@@ -1,58 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe CanCan::AccessDenied do
4
- describe "with action and subject" do
5
- before(:each) do
6
- @exception = CanCan::AccessDenied.new(nil, :some_action, :some_subject)
7
- end
8
-
9
- it "has action and subject accessors" do
10
- expect(@exception.action).to eq(:some_action)
11
- expect(@exception.subject).to eq(:some_subject)
12
- end
13
-
14
- it "has a changable default message" do
15
- expect(@exception.message).to eq("You are not authorized to access this page.")
16
- @exception.default_message = "Unauthorized!"
17
- expect(@exception.message).to eq("Unauthorized!")
18
- end
19
- end
20
-
21
- describe "with only a message" do
22
- before(:each) do
23
- @exception = CanCan::AccessDenied.new("Access denied!")
24
- end
25
-
26
- it "has nil action and subject" do
27
- expect(@exception.action).to be_nil
28
- expect(@exception.subject).to be_nil
29
- end
30
-
31
- it "has passed message" do
32
- expect(@exception.message).to eq("Access denied!")
33
- end
34
- end
35
-
36
- describe "i18n in the default message" do
37
- after(:each) do
38
- I18n.backend = nil
39
- end
40
-
41
- it "uses i18n for the default message" do
42
- I18n.backend.store_translations :en, :unauthorized => {:default => "This is a different message"}
43
- @exception = CanCan::AccessDenied.new
44
- expect(@exception.message).to eq("This is a different message")
45
- end
46
-
47
- it "defaults to a nice message" do
48
- @exception = CanCan::AccessDenied.new
49
- expect(@exception.message).to eq("You are not authorized to access this page.")
50
- end
51
-
52
- it "does not use translation if a message is given" do
53
- @exception = CanCan::AccessDenied.new("Hey! You're not welcome here")
54
- expect(@exception.message).to eq("Hey! You're not welcome here")
55
- expect(@exception.message).to_not eq("You are not authorized to access this page.")
56
- end
57
- end
58
- end
@@ -1,71 +0,0 @@
1
- require "spec_helper"
2
-
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
-
9
- before(:each) do
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 => {}} }
23
- end
24
-
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)
30
- end
31
-
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)
37
- end
38
-
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)
44
- end
45
-
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)
52
- end
53
-
54
- it "builds a new resource with attributes from current ability" do
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)
59
- resource.load_resource
60
- expect(controller.instance_variable_get(:@model).name).to eq("from conditions")
61
- end
62
-
63
- it "overrides initial attributes with params" do
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)
68
- resource.load_resource
69
- expect(controller.instance_variable_get(:@model).name).to eq("from params")
70
- end
71
- end
@@ -1,29 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe "be_able_to" do
4
- it "delegates to can?" do
5
- expect(object = double).to receive(:can?).with(:read, 123) { true }
6
- expect(object).to be_able_to(:read, 123)
7
- end
8
-
9
- it "reports a nice failure message for should" do
10
- expect(object = double).to receive(:can?).with(:read, 123) { false }
11
- expect {
12
- expect(object).to be_able_to(:read, 123)
13
- }.to raise_error('expected to be able to :read 123')
14
- end
15
-
16
- it "reports a nice failure message for should not" do
17
- expect(object = double).to receive(:can?).with(:read, 123) { true }
18
- expect {
19
- expect(object).to_not be_able_to(:read, 123)
20
- }.to raise_error('expected not to be able to :read 123')
21
- end
22
-
23
- it "delegates additional arguments to can? and reports in failure message" do
24
- expect(object = double).to receive(:can?).with(:read, 123, 456) { false }
25
- expect {
26
- expect(object).to be_able_to(:read, 123, 456)
27
- }.to raise_error('expected to be able to :read 123 456')
28
- end
29
- end
@@ -1,40 +0,0 @@
1
- require "spec_helper"
2
-
3
- if defined? CanCan::ModelAdapters::ActiveRecord4Adapter
4
- describe CanCan::ModelAdapters::ActiveRecord4Adapter do
5
- before :each do
6
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
7
- ActiveRecord::Migration.verbose = false
8
- ActiveRecord::Schema.define do
9
- create_table(:parents) do |t|
10
- t.timestamps :null => false
11
- end
12
-
13
- create_table(:children) do |t|
14
- t.timestamps :null => false
15
- t.integer :parent_id
16
- end
17
- end
18
-
19
- class Parent < ActiveRecord::Base
20
- has_many :children, lambda { order(:id => :desc) }
21
- end
22
-
23
- class Child < ActiveRecord::Base
24
- belongs_to :parent
25
- end
26
-
27
- (@ability = double).extend(CanCan::Ability)
28
- end
29
-
30
- it "respects scope on included associations" do
31
- @ability.can :read, [Parent, Child]
32
-
33
- parent = Parent.create!
34
- child1 = Child.create!(:parent => parent, :created_at => 1.hours.ago)
35
- child2 = Child.create!(:parent => parent, :created_at => 2.hours.ago)
36
-
37
- expect(Parent.accessible_by(@ability).order(:created_at => :asc).includes(:children).first.children).to eq [child2, child1]
38
- end
39
- end
40
- end
@@ -1,446 +0,0 @@
1
- require "spec_helper"
2
-
3
- if defined? CanCan::ModelAdapters::ActiveRecordAdapter
4
-
5
- describe CanCan::ModelAdapters::ActiveRecordAdapter do
6
-
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 :null => false
15
- end
16
-
17
- create_table(:projects) do |t|
18
- t.string :name
19
- t.timestamps :null => false
20
- end
21
-
22
- create_table(:articles) do |t|
23
- t.string :name
24
- t.timestamps :null => false
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 :null => false
36
- end
37
-
38
- create_table(:legacy_mentions) do |t|
39
- t.integer :user_id
40
- t.integer :article_id
41
- t.timestamps :null => false
42
- end
43
-
44
- create_table(:users) do |t|
45
- t.timestamps :null => false
46
- end
47
- end
48
-
49
- class Project < ActiveRecord::Base
50
- end
51
-
52
- class Category < ActiveRecord::Base
53
- has_many :articles
54
- end
55
-
56
- class Article < ActiveRecord::Base
57
- belongs_to :category
58
- has_many :comments
59
- has_many :mentions
60
- has_many :mentioned_users, :through => :mentions, :source => :user
61
- belongs_to :user
62
- end
63
-
64
- class Mention < ActiveRecord::Base
65
- self.table_name = 'legacy_mentions'
66
- belongs_to :user
67
- belongs_to :article
68
- end
69
-
70
- class Comment < ActiveRecord::Base
71
- belongs_to :article
72
- end
73
-
74
- class User < ActiveRecord::Base
75
- has_many :articles
76
- end
77
-
78
- (@ability = double).extend(CanCan::Ability)
79
- @article_table = Article.table_name
80
- @comment_table = Comment.table_name
81
- end
82
-
83
- it "is for only active record classes" do
84
- if ActiveRecord.respond_to?(:version) &&
85
- ActiveRecord.version > Gem::Version.new("4")
86
- expect(CanCan::ModelAdapters::ActiveRecord4Adapter).to_not be_for_class(Object)
87
- expect(CanCan::ModelAdapters::ActiveRecord4Adapter).to be_for_class(Article)
88
- expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::ActiveRecord4Adapter)
89
- else
90
- expect(CanCan::ModelAdapters::ActiveRecord3Adapter).to_not be_for_class(Object)
91
- expect(CanCan::ModelAdapters::ActiveRecord3Adapter).to be_for_class(Article)
92
- expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::ActiveRecord3Adapter)
93
- end
94
- end
95
-
96
- it "finds record" do
97
- article = Article.create!
98
- adapter = CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)
99
- expect(adapter.find(Article, article.id)).to eq(article)
100
- end
101
-
102
- it "does not fetch any records when no abilities are defined" do
103
- Article.create!
104
- expect(Article.accessible_by(@ability)).to be_empty
105
- end
106
-
107
- it "fetches all articles when one can read all" do
108
- @ability.can :read, Article
109
- article = Article.create!
110
- expect(Article.accessible_by(@ability)).to eq([article])
111
- end
112
-
113
- it "fetches only the articles that are published" do
114
- @ability.can :read, Article, :published => true
115
- article1 = Article.create!(:published => true)
116
- article2 = Article.create!(:published => false)
117
- expect(Article.accessible_by(@ability)).to eq([article1])
118
- end
119
-
120
- it "fetches any articles which are published or secret" do
121
- @ability.can :read, Article, :published => true
122
- @ability.can :read, Article, :secret => true
123
- article1 = Article.create!(:published => true, :secret => false)
124
- article2 = Article.create!(:published => true, :secret => true)
125
- article3 = Article.create!(:published => false, :secret => true)
126
- article4 = Article.create!(:published => false, :secret => false)
127
- expect(Article.accessible_by(@ability)).to eq([article1, article2, article3])
128
- end
129
-
130
- it "fetches any articles which we are cited in" do
131
- user = User.create!
132
- cited = Article.create!
133
- not_cited = Article.create!
134
- cited.mentioned_users << user
135
- @ability.can :read, Article, { :mentioned_users => { :id => user.id } }
136
- @ability.can :read, Article, { :mentions => { :user_id => user.id } }
137
- expect(Article.accessible_by(@ability)).to eq([cited])
138
- end
139
-
140
- it "fetches only the articles that are published and not secret" do
141
- @ability.can :read, Article, :published => true
142
- @ability.cannot :read, Article, :secret => true
143
- article1 = Article.create!(:published => true, :secret => false)
144
- article2 = Article.create!(:published => true, :secret => true)
145
- article3 = Article.create!(:published => false, :secret => true)
146
- article4 = Article.create!(:published => false, :secret => false)
147
- expect(Article.accessible_by(@ability)).to eq([article1])
148
- end
149
-
150
- it "only reads comments for articles which are published" do
151
- @ability.can :read, Comment, :article => { :published => true }
152
- comment1 = Comment.create!(:article => Article.create!(:published => true))
153
- comment2 = Comment.create!(:article => Article.create!(:published => false))
154
- expect(Comment.accessible_by(@ability)).to eq([comment1])
155
- end
156
-
157
- it "should only read articles which are published or in visible categories" do
158
- @ability.can :read, Article, :category => { :visible => true }
159
- @ability.can :read, Article, :published => true
160
- article1 = Article.create!(:published => true)
161
- article2 = Article.create!(:published => false)
162
- article3 = Article.create!(:published => false, :category => Category.create!(:visible => true))
163
- expect(Article.accessible_by(@ability)).to eq([article1, article3])
164
- end
165
-
166
- it "should only read categories once even if they have multiple articles" do
167
- @ability.can :read, Category, :articles => { :published => true }
168
- @ability.can :read, Article, :published => true
169
- category = Category.create!
170
- Article.create!(:published => true, :category => category)
171
- Article.create!(:published => true, :category => category)
172
- expect(Category.accessible_by(@ability)).to eq([category])
173
- end
174
-
175
- it "only reads comments for visible categories through articles" do
176
- @ability.can :read, Comment, :article => { :category => { :visible => true } }
177
- comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true)))
178
- comment2 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => false)))
179
- expect(Comment.accessible_by(@ability)).to eq([comment1])
180
- end
181
-
182
- it "allows conditions in SQL and merge with hash conditions" do
183
- @ability.can :read, Article, :published => true
184
- @ability.can :read, Article, ["secret=?", true]
185
- article1 = Article.create!(:published => true, :secret => false)
186
- article2 = Article.create!(:published => true, :secret => true)
187
- article3 = Article.create!(:published => false, :secret => true)
188
- article4 = Article.create!(:published => false, :secret => false)
189
- expect(Article.accessible_by(@ability)).to eq([article1, article2, article3])
190
- end
191
-
192
- it "allows a scope for conditions" do
193
- @ability.can :read, Article, Article.where(:secret => true)
194
- article1 = Article.create!(:secret => true)
195
- article2 = Article.create!(:secret => false)
196
- expect(Article.accessible_by(@ability)).to eq([article1])
197
- end
198
-
199
- it "fetches only associated records when using with a scope for conditions" do
200
- @ability.can :read, Article, Article.where(:secret => true)
201
- category1 = Category.create!(:visible => false)
202
- category2 = Category.create!(:visible => true)
203
- article1 = Article.create!(:secret => true, :category => category1)
204
- article2 = Article.create!(:secret => true, :category => category2)
205
- expect(category1.articles.accessible_by(@ability)).to eq([article1])
206
- end
207
-
208
- it "raises an exception when trying to merge scope with other conditions" do
209
- @ability.can :read, Article, :published => true
210
- @ability.can :read, Article, Article.where(:secret => true)
211
- expect(lambda { Article.accessible_by(@ability) }).to raise_error(CanCan::Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Article ability.")
212
- end
213
-
214
- it "does not allow to fetch records when ability with just block present" do
215
- @ability.can :read, Article do
216
- false
217
- end
218
- expect(lambda { Article.accessible_by(@ability) }).to raise_error(CanCan::Error)
219
- end
220
-
221
- it "should support more than one deeply nested conditions" do
222
- @ability.can :read, Comment, :article => {
223
- :category => {
224
- :name => 'foo', :visible => true
225
- }
226
- }
227
- expect { Comment.accessible_by(@ability) }.to_not raise_error
228
- end
229
-
230
- it "does not allow to check ability on object against SQL conditions without block" do
231
- @ability.can :read, Article, ["secret=?", true]
232
- expect(lambda { @ability.can? :read, Article.new }).to raise_error(CanCan::Error)
233
- end
234
-
235
- it "has false conditions if no abilities match" do
236
- expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'")
237
- end
238
-
239
- it "returns false conditions for cannot clause" do
240
- @ability.cannot :read, Article
241
- expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'")
242
- end
243
-
244
- it "returns SQL for single `can` definition in front of default `cannot` condition" do
245
- @ability.cannot :read, Article
246
- @ability.can :read, Article, :published => false, :secret => true
247
- expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't'])
248
- end
249
-
250
- it "returns true condition for single `can` definition in front of default `can` condition" do
251
- @ability.can :read, Article
252
- @ability.can :read, Article, :published => false, :secret => true
253
- expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'")
254
- end
255
-
256
- it "returns `false condition` for single `cannot` definition in front of default `cannot` condition" do
257
- @ability.cannot :read, Article
258
- @ability.cannot :read, Article, :published => false, :secret => true
259
- expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'")
260
- end
261
-
262
- it "returns `not (sql)` for single `cannot` definition in front of default `can` condition" do
263
- @ability.can :read, Article
264
- @ability.cannot :read, Article, :published => false, :secret => true
265
- expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["not (#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't')])
266
- end
267
-
268
- it "returns appropriate sql conditions in complex case" do
269
- @ability.can :read, Article
270
- @ability.can :manage, Article, :id => 1
271
- @ability.can :update, Article, :published => true
272
- @ability.cannot :update, Article, :secret => true
273
- expect(@ability.model_adapter(Article, :update).conditions).to eq(%Q[not ("#{@article_table}"."secret" = 't') AND (("#{@article_table}"."published" = 't') OR ("#{@article_table}"."id" = 1))])
274
- expect(@ability.model_adapter(Article, :manage).conditions).to eq({:id => 1})
275
- expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'")
276
- end
277
-
278
- it "returns appropriate sql conditions in complex case with nested joins" do
279
- @ability.can :read, Comment, :article => { :category => { :visible => true } }
280
- expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Category.table_name.to_sym => { :visible => true } })
281
- end
282
-
283
- it "returns appropriate sql conditions in complex case with nested joins of different depth" do
284
- @ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } }
285
- expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } })
286
- end
287
-
288
- it "does not forget conditions when calling with SQL string" do
289
- @ability.can :read, Article, :published => true
290
- @ability.can :read, Article, ['secret=?', false]
291
- adapter = @ability.model_adapter(Article, :read)
292
- 2.times do
293
- expect(adapter.conditions).to eq(%Q[(secret='f') OR ("#{@article_table}"."published" = 't')])
294
- end
295
- end
296
-
297
- it "has nil joins if no rules" do
298
- expect(@ability.model_adapter(Article, :read).joins).to be_nil
299
- end
300
-
301
- it "has nil joins if no nested hashes specified in conditions" do
302
- @ability.can :read, Article, :published => false
303
- @ability.can :read, Article, :secret => true
304
- expect(@ability.model_adapter(Article, :read).joins).to be_nil
305
- end
306
-
307
- it "merges separate joins into a single array" do
308
- @ability.can :read, Article, :project => { :blocked => false }
309
- @ability.can :read, Article, :company => { :admin => true }
310
- expect(@ability.model_adapter(Article, :read).joins.inspect).to orderlessly_match([:company, :project].inspect)
311
- end
312
-
313
- it "merges same joins into a single array" do
314
- @ability.can :read, Article, :project => { :blocked => false }
315
- @ability.can :read, Article, :project => { :admin => true }
316
- expect(@ability.model_adapter(Article, :read).joins).to eq([:project])
317
- end
318
-
319
- it "merges nested and non-nested joins" do
320
- @ability.can :read, Article, :project => { :blocked => false }
321
- @ability.can :read, Article, :project => { :comments => { :spam => true } }
322
- expect(@ability.model_adapter(Article, :read).joins).to eq([{:project=>[:comments]}])
323
- end
324
-
325
- it "merges :all conditions with other conditions" do
326
- user = User.create!
327
- article = Article.create!(:user => user)
328
- ability = Ability.new(user)
329
- ability.can :manage, :all
330
- ability.can :manage, Article, :user_id => user.id
331
- expect(Article.accessible_by(ability)).to eq([article])
332
- end
333
-
334
- it 'should not execute a scope when checking ability on the class' do
335
- relation = Article.where(:secret => true)
336
- @ability.can :read, Article, relation do |article|
337
- article.secret == true
338
- end
339
-
340
- allow(relation).to receive(:count).and_raise('Unexpected scope execution.')
341
-
342
- expect { @ability.can? :read, Article }.not_to raise_error
343
- end
344
-
345
- context "with namespaced models" do
346
- before :each do
347
- ActiveRecord::Schema.define do
348
- create_table( :table_xes ) do |t|
349
- t.timestamps :null => false
350
- end
351
-
352
- create_table( :table_zs ) do |t|
353
- t.integer :table_x_id
354
- t.integer :user_id
355
- t.timestamps :null => false
356
- end
357
- end
358
-
359
- module Namespace
360
- end
361
-
362
- class Namespace::TableX < ActiveRecord::Base
363
- has_many :table_zs
364
- end
365
-
366
- class Namespace::TableZ < ActiveRecord::Base
367
- belongs_to :table_x
368
- belongs_to :user
369
- end
370
- end
371
-
372
- it "fetches all namespace::table_x when one is related by table_y" do
373
- user = User.create!
374
-
375
- ability = Ability.new(user)
376
- ability.can :read, Namespace::TableX, :table_zs => { :user_id => user.id }
377
-
378
- table_x = Namespace::TableX.create!
379
- table_z = table_x.table_zs.create( :user => user )
380
- expect(Namespace::TableX.accessible_by(ability)).to eq([table_x])
381
- end
382
- end
383
-
384
- context "when MetaWhere is defined" do
385
- before :each do
386
- pending "[Deprecated] MetaWhere support is being removed" unless defined? MetaWhere
387
- end
388
-
389
- it "restricts articles given a MetaWhere condition" do
390
- # pending "[Deprecated] MetaWhere support is being removed" unless defined? MetaWhere
391
- @ability.can :read, Article, :priority.lt => 2
392
- article1 = Article.create!(:priority => 1)
393
- article2 = Article.create!(:priority => 3)
394
- expect(Article.accessible_by(@ability)).to eq([article1])
395
- expect(@ability).to be_able_to(:read, article1)
396
- expect(@ability).to_not be_able_to(:read, article2)
397
- end
398
-
399
- it "merges MetaWhere and non-MetaWhere conditions" do
400
- # pending "[Deprecated] MetaWhere support is being removed" unless defined? MetaWhere
401
- @ability.can :read, Article, :priority.lt => 2
402
- @ability.can :read, Article, :priority => 1
403
- article1 = Article.create!(:priority => 1)
404
- article2 = Article.create!(:priority => 3)
405
- expect(Article.accessible_by(@ability)).to eq([article1])
406
- expect(@ability).to be_able_to(:read, article1)
407
- expect(@ability).to_not be_able_to(:read, article2)
408
- end
409
-
410
- it "matches any MetaWhere condition" do
411
- adapter = CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)
412
- article1 = Article.new(:priority => 1, :name => "Hello World")
413
- expect(adapter.matches_condition?(article1, :priority.eq, 1)).to be(true)
414
- expect(adapter.matches_condition?(article1, :priority.eq, 2)).to be(false)
415
- expect(adapter.matches_condition?(article1, :priority.eq_any, [1, 2])).to be(true)
416
- expect(adapter.matches_condition?(article1, :priority.eq_any, [2, 3])).to be(false)
417
- expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 1])).to be(true)
418
- expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 2])).to be(false)
419
- expect(adapter.matches_condition?(article1, :priority.ne, 2)).to be(true)
420
- expect(adapter.matches_condition?(article1, :priority.ne, 1)).to be(false)
421
- expect(adapter.matches_condition?(article1, :priority.in, [1, 2])).to be(true)
422
- expect(adapter.matches_condition?(article1, :priority.in, [2, 3])).to be(false)
423
- expect(adapter.matches_condition?(article1, :priority.nin, [2, 3])).to be(true)
424
- expect(adapter.matches_condition?(article1, :priority.nin, [1, 2])).to be(false)
425
- expect(adapter.matches_condition?(article1, :priority.lt, 2)).to be(true)
426
- expect(adapter.matches_condition?(article1, :priority.lt, 1)).to be(false)
427
- expect(adapter.matches_condition?(article1, :priority.lteq, 1)).to be(true)
428
- expect(adapter.matches_condition?(article1, :priority.lteq, 0)).to be(false)
429
- expect(adapter.matches_condition?(article1, :priority.gt, 0)).to be(true)
430
- expect(adapter.matches_condition?(article1, :priority.gt, 1)).to be(false)
431
- expect(adapter.matches_condition?(article1, :priority.gteq, 1)).to be(true)
432
- expect(adapter.matches_condition?(article1, :priority.gteq, 2)).to be(false)
433
- expect(adapter.matches_condition?(article1, :name.like, "%ello worl%")).to be_truthy
434
- expect(adapter.matches_condition?(article1, :name.like, "hello world")).to be_truthy
435
- expect(adapter.matches_condition?(article1, :name.like, "hello%")).to be_truthy
436
- expect(adapter.matches_condition?(article1, :name.like, "h%d")).to be_truthy
437
- expect(adapter.matches_condition?(article1, :name.like, "%helo%")).to be_falsey
438
- expect(adapter.matches_condition?(article1, :name.like, "hello")).to be_falsey
439
- expect(adapter.matches_condition?(article1, :name.like, "hello.world")).to be_falsey
440
- # For some reason this is reporting "The not_matches MetaWhere condition is not supported."
441
- # expect(adapter.matches_condition?(article1, :name.nlike, "%helo%")).to be(true)
442
- # expect(adapter.matches_condition?(article1, :name.nlike, "%ello worl%")).to be(false)
443
- end
444
- end
445
- end
446
- end