cancancan 1.7.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 (42) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG.rdoc +427 -0
  3. data/CONTRIBUTING.md +11 -0
  4. data/Gemfile +23 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +161 -0
  7. data/Rakefile +18 -0
  8. data/init.rb +1 -0
  9. data/lib/cancan.rb +13 -0
  10. data/lib/cancan/ability.rb +324 -0
  11. data/lib/cancan/controller_additions.rb +397 -0
  12. data/lib/cancan/controller_resource.rb +286 -0
  13. data/lib/cancan/exceptions.rb +50 -0
  14. data/lib/cancan/inherited_resource.rb +20 -0
  15. data/lib/cancan/matchers.rb +14 -0
  16. data/lib/cancan/model_adapters/abstract_adapter.rb +56 -0
  17. data/lib/cancan/model_adapters/active_record_adapter.rb +180 -0
  18. data/lib/cancan/model_adapters/data_mapper_adapter.rb +34 -0
  19. data/lib/cancan/model_adapters/default_adapter.rb +7 -0
  20. data/lib/cancan/model_adapters/mongoid_adapter.rb +54 -0
  21. data/lib/cancan/model_additions.rb +31 -0
  22. data/lib/cancan/rule.rb +147 -0
  23. data/lib/cancancan.rb +1 -0
  24. data/lib/generators/cancan/ability/USAGE +4 -0
  25. data/lib/generators/cancan/ability/ability_generator.rb +11 -0
  26. data/lib/generators/cancan/ability/templates/ability.rb +32 -0
  27. data/spec/README.rdoc +28 -0
  28. data/spec/cancan/ability_spec.rb +455 -0
  29. data/spec/cancan/controller_additions_spec.rb +141 -0
  30. data/spec/cancan/controller_resource_spec.rb +553 -0
  31. data/spec/cancan/exceptions_spec.rb +58 -0
  32. data/spec/cancan/inherited_resource_spec.rb +60 -0
  33. data/spec/cancan/matchers_spec.rb +29 -0
  34. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +358 -0
  35. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +118 -0
  36. data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
  37. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +226 -0
  38. data/spec/cancan/rule_spec.rb +52 -0
  39. data/spec/matchers.rb +13 -0
  40. data/spec/spec.opts +2 -0
  41. data/spec/spec_helper.rb +77 -0
  42. metadata +126 -0
@@ -0,0 +1,58 @@
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
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+
3
+ describe CanCan::InheritedResource do
4
+ before(:each) do
5
+ @params = HashWithIndifferentAccess.new(:controller => "projects")
6
+ @controller_class = Class.new
7
+ @controller = @controller_class.new
8
+ @ability = Ability.new(nil)
9
+ allow(@controller).to receive(:params).and_return { @params }
10
+ allow(@controller).to receive(:current_ability) { @ability }
11
+ allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} }
12
+ end
13
+
14
+ it "show loads resource through @controller.resource" do
15
+ @params.merge!(:action => "show", :id => 123)
16
+ allow(@controller).to receive(:resource) { :project_resource }
17
+ CanCan::InheritedResource.new(@controller).load_resource
18
+ expect(@controller.instance_variable_get(:@project)).to eq(:project_resource)
19
+ end
20
+
21
+ it "new loads through @controller.build_resource" do
22
+ @params[:action] = "new"
23
+ allow(@controller).to receive(:build_resource) { :project_resource }
24
+ CanCan::InheritedResource.new(@controller).load_resource
25
+ expect(@controller.instance_variable_get(:@project)).to eq(:project_resource)
26
+ end
27
+
28
+ it "index loads through @controller.association_chain when parent" do
29
+ @params[:action] = "index"
30
+ allow(@controller).to receive(:association_chain) { @controller.instance_variable_set(:@project, :project_resource) }
31
+ CanCan::InheritedResource.new(@controller, :parent => true).load_resource
32
+ expect(@controller.instance_variable_get(:@project)).to eq(:project_resource)
33
+ end
34
+
35
+ it "index loads through @controller.end_of_association_chain" do
36
+ @params[:action] = "index"
37
+ allow(Project).to receive(:accessible_by).with(@ability, :index) { :projects }
38
+ allow(@controller).to receive(:end_of_association_chain) { Project }
39
+ CanCan::InheritedResource.new(@controller).load_resource
40
+ expect(@controller.instance_variable_get(:@projects)).to eq(:projects)
41
+ end
42
+
43
+ it "builds a new resource with attributes from current ability" do
44
+ @params[:action] = "new"
45
+ @ability.can(:create, Project, :name => "from conditions")
46
+ allow(@controller).to receive(:build_resource) { Struct.new(:name).new }
47
+ resource = CanCan::InheritedResource.new(@controller)
48
+ resource.load_resource
49
+ expect(@controller.instance_variable_get(:@project).name).to eq("from conditions")
50
+ end
51
+
52
+ it "overrides initial attributes with params" do
53
+ @params.merge!(:action => "new", :project => {:name => "from params"})
54
+ @ability.can(:create, Project, :name => "from conditions")
55
+ allow(@controller).to receive(:build_resource) { Struct.new(:name).new }
56
+ resource = CanCan::ControllerResource.new(@controller)
57
+ resource.load_resource
58
+ expect(@controller.instance_variable_get(:@project).name).to eq("from params")
59
+ end
60
+ end
@@ -0,0 +1,29 @@
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
@@ -0,0 +1,358 @@
1
+ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
2
+ require "spec_helper"
3
+
4
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
5
+
6
+ describe CanCan::ModelAdapters::ActiveRecordAdapter do
7
+ with_model :category do
8
+ table do |t|
9
+ t.string "name"
10
+ t.boolean "visible"
11
+ end
12
+ model do
13
+ has_many :articles
14
+ end
15
+ end
16
+
17
+ with_model :article do
18
+ table do |t|
19
+ t.string "name"
20
+ t.boolean "published"
21
+ t.boolean "secret"
22
+ t.integer "priority"
23
+ t.integer "category_id"
24
+ t.integer "user_id"
25
+ end
26
+ model do
27
+ belongs_to :category
28
+ has_many :comments
29
+ belongs_to :user
30
+ end
31
+ end
32
+
33
+ with_model :comment do
34
+ table do |t|
35
+ t.boolean "spam"
36
+ t.integer "article_id"
37
+ end
38
+ model do
39
+ belongs_to :article
40
+ end
41
+ end
42
+
43
+ with_model :user do
44
+ table do |t|
45
+
46
+ end
47
+ model do
48
+ has_many :articles
49
+ end
50
+ end
51
+
52
+ before(:each) do
53
+ Article.delete_all
54
+ Comment.delete_all
55
+ (@ability = double).extend(CanCan::Ability)
56
+ @article_table = Article.table_name
57
+ @comment_table = Comment.table_name
58
+ end
59
+
60
+ it "is for only active record classes" do
61
+ expect(CanCan::ModelAdapters::ActiveRecordAdapter).to_not be_for_class(Object)
62
+ expect(CanCan::ModelAdapters::ActiveRecordAdapter).to be_for_class(Article)
63
+ expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::ActiveRecordAdapter)
64
+ end
65
+
66
+ it "finds record" do
67
+ article = Article.create!
68
+ expect(CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id)).to eq(article)
69
+ end
70
+
71
+ it "does not fetch any records when no abilities are defined" do
72
+ Article.create!
73
+ expect(Article.accessible_by(@ability)).to be_empty
74
+ end
75
+
76
+ it "fetches all articles when one can read all" do
77
+ @ability.can :read, Article
78
+ article = Article.create!
79
+ expect(Article.accessible_by(@ability)).to eq([article])
80
+ end
81
+
82
+ it "fetches only the articles that are published" do
83
+ @ability.can :read, Article, :published => true
84
+ article1 = Article.create!(:published => true)
85
+ article2 = Article.create!(:published => false)
86
+ expect(Article.accessible_by(@ability)).to eq([article1])
87
+ end
88
+
89
+ it "fetches any articles which are published or secret" do
90
+ @ability.can :read, Article, :published => true
91
+ @ability.can :read, Article, :secret => true
92
+ article1 = Article.create!(:published => true, :secret => false)
93
+ article2 = Article.create!(:published => true, :secret => true)
94
+ article3 = Article.create!(:published => false, :secret => true)
95
+ article4 = Article.create!(:published => false, :secret => false)
96
+ expect(Article.accessible_by(@ability)).to eq([article1, article2, article3])
97
+ end
98
+
99
+ it "fetches only the articles that are published and not secret" do
100
+ @ability.can :read, Article, :published => true
101
+ @ability.cannot :read, Article, :secret => true
102
+ article1 = Article.create!(:published => true, :secret => false)
103
+ article2 = Article.create!(:published => true, :secret => true)
104
+ article3 = Article.create!(:published => false, :secret => true)
105
+ article4 = Article.create!(:published => false, :secret => false)
106
+ expect(Article.accessible_by(@ability)).to eq([article1])
107
+ end
108
+
109
+ it "only reads comments for articles which are published" do
110
+ @ability.can :read, Comment, :article => { :published => true }
111
+ comment1 = Comment.create!(:article => Article.create!(:published => true))
112
+ comment2 = Comment.create!(:article => Article.create!(:published => false))
113
+ expect(Comment.accessible_by(@ability)).to eq([comment1])
114
+ end
115
+
116
+ it "should only read articles which are published or in visible categories" do
117
+ @ability.can :read, Article, :category => { :visible => true }
118
+ @ability.can :read, Article, :published => true
119
+ article1 = Article.create!(:published => true)
120
+ article2 = Article.create!(:published => false)
121
+ article3 = Article.create!(:published => false, :category => Category.create!(:visible => true))
122
+ expect(Article.accessible_by(@ability)).to eq([article1, article3])
123
+ end
124
+
125
+ it "should only read categories once even if they have multiple articles" do
126
+ @ability.can :read, Category, :articles => { :published => true }
127
+ @ability.can :read, Article, :published => true
128
+ category = Category.create!
129
+ Article.create!(:published => true, :category => category)
130
+ Article.create!(:published => true, :category => category)
131
+ expect(Category.accessible_by(@ability)).to eq([category])
132
+ end
133
+
134
+ it "only reads comments for visible categories through articles" do
135
+ @ability.can :read, Comment, :article => { :category => { :visible => true } }
136
+ comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true)))
137
+ comment2 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => false)))
138
+ expect(Comment.accessible_by(@ability)).to eq([comment1])
139
+ end
140
+
141
+ it "allows conditions in SQL and merge with hash conditions" do
142
+ @ability.can :read, Article, :published => true
143
+ @ability.can :read, Article, ["secret=?", true]
144
+ article1 = Article.create!(:published => true, :secret => false)
145
+ article2 = Article.create!(:published => true, :secret => true)
146
+ article3 = Article.create!(:published => false, :secret => true)
147
+ article4 = Article.create!(:published => false, :secret => false)
148
+ expect(Article.accessible_by(@ability)).to eq([article1, article2, article3])
149
+ end
150
+
151
+ it "allows a scope for conditions" do
152
+ @ability.can :read, Article, Article.where(:secret => true)
153
+ article1 = Article.create!(:secret => true)
154
+ article2 = Article.create!(:secret => false)
155
+ expect(Article.accessible_by(@ability)).to eq([article1])
156
+ end
157
+
158
+ it "fetches only associated records when using with a scope for conditions" do
159
+ @ability.can :read, Article, Article.where(:secret => true)
160
+ category1 = Category.create!(:visible => false)
161
+ category2 = Category.create!(:visible => true)
162
+ article1 = Article.create!(:secret => true, :category => category1)
163
+ article2 = Article.create!(:secret => true, :category => category2)
164
+ expect(category1.articles.accessible_by(@ability)).to eq([article1])
165
+ end
166
+
167
+ it "raises an exception when trying to merge scope with other conditions" do
168
+ @ability.can :read, Article, :published => true
169
+ @ability.can :read, Article, Article.where(:secret => true)
170
+ 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.")
171
+ end
172
+
173
+ it "does not allow to fetch records when ability with just block present" do
174
+ @ability.can :read, Article do
175
+ false
176
+ end
177
+ expect(lambda { Article.accessible_by(@ability) }).to raise_error(CanCan::Error)
178
+ end
179
+
180
+ it "should support more than one deeply nested conditions" do
181
+ @ability.can :read, Comment, :article => {
182
+ :category => {
183
+ :name => 'foo', :visible => true
184
+ }
185
+ }
186
+ expect { Comment.accessible_by(@ability) }.to_not raise_error
187
+ end
188
+
189
+ it "does not allow to check ability on object against SQL conditions without block" do
190
+ @ability.can :read, Article, ["secret=?", true]
191
+ expect(lambda { @ability.can? :read, Article.new }).to raise_error(CanCan::Error)
192
+ end
193
+
194
+ it "has false conditions if no abilities match" do
195
+ expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'")
196
+ end
197
+
198
+ it "returns false conditions for cannot clause" do
199
+ @ability.cannot :read, Article
200
+ expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'")
201
+ end
202
+
203
+ it "returns SQL for single `can` definition in front of default `cannot` condition" do
204
+ @ability.cannot :read, Article
205
+ @ability.can :read, Article, :published => false, :secret => true
206
+ expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't'])
207
+ end
208
+
209
+ it "returns true condition for single `can` definition in front of default `can` condition" do
210
+ @ability.can :read, Article
211
+ @ability.can :read, Article, :published => false, :secret => true
212
+ expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'")
213
+ end
214
+
215
+ it "returns `false condition` for single `cannot` definition in front of default `cannot` condition" do
216
+ @ability.cannot :read, Article
217
+ @ability.cannot :read, Article, :published => false, :secret => true
218
+ expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'")
219
+ end
220
+
221
+ it "returns `not (sql)` for single `cannot` definition in front of default `can` condition" do
222
+ @ability.can :read, Article
223
+ @ability.cannot :read, Article, :published => false, :secret => true
224
+ expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["not (#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't')])
225
+ end
226
+
227
+ it "returns appropriate sql conditions in complex case" do
228
+ @ability.can :read, Article
229
+ @ability.can :manage, Article, :id => 1
230
+ @ability.can :update, Article, :published => true
231
+ @ability.cannot :update, Article, :secret => true
232
+ 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))])
233
+ expect(@ability.model_adapter(Article, :manage).conditions).to eq({:id => 1})
234
+ expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'")
235
+ end
236
+
237
+ it "returns appropriate sql conditions in complex case with nested joins" do
238
+ @ability.can :read, Comment, :article => { :category => { :visible => true } }
239
+ expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Category.table_name.to_sym => { :visible => true } })
240
+ end
241
+
242
+ it "returns appropriate sql conditions in complex case with nested joins of different depth" do
243
+ @ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } }
244
+ expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } })
245
+ end
246
+
247
+ it "does not forget conditions when calling with SQL string" do
248
+ @ability.can :read, Article, :published => true
249
+ @ability.can :read, Article, ['secret=?', false]
250
+ adapter = @ability.model_adapter(Article, :read)
251
+ 2.times do
252
+ expect(adapter.conditions).to eq(%Q[(secret='f') OR ("#{@article_table}"."published" = 't')])
253
+ end
254
+ end
255
+
256
+ it "has nil joins if no rules" do
257
+ expect(@ability.model_adapter(Article, :read).joins).to be_nil
258
+ end
259
+
260
+ it "has nil joins if no nested hashes specified in conditions" do
261
+ @ability.can :read, Article, :published => false
262
+ @ability.can :read, Article, :secret => true
263
+ expect(@ability.model_adapter(Article, :read).joins).to be_nil
264
+ end
265
+
266
+ it "merges separate joins into a single array" do
267
+ @ability.can :read, Article, :project => { :blocked => false }
268
+ @ability.can :read, Article, :company => { :admin => true }
269
+ expect(@ability.model_adapter(Article, :read).joins.inspect).to orderlessly_match([:company, :project].inspect)
270
+ end
271
+
272
+ it "merges same joins into a single array" do
273
+ @ability.can :read, Article, :project => { :blocked => false }
274
+ @ability.can :read, Article, :project => { :admin => true }
275
+ expect(@ability.model_adapter(Article, :read).joins).to eq([:project])
276
+ end
277
+
278
+ it "merges nested and non-nested joins" do
279
+ @ability.can :read, Article, :project => { :blocked => false }
280
+ @ability.can :read, Article, :project => { :comments => { :spam => true } }
281
+ expect(@ability.model_adapter(Article, :read).joins).to eq([{:project=>[:comments]}])
282
+ end
283
+
284
+ it "merges :all conditions with other conditions" do
285
+ user = User.create!
286
+ article = Article.create!(:user => user)
287
+ ability = Ability.new(user)
288
+ ability.can :manage, :all
289
+ ability.can :manage, Article, :user_id => user.id
290
+ expect(Article.accessible_by(ability)).to eq([article])
291
+ end
292
+
293
+ it "restricts articles given a MetaWhere condition" do
294
+ @ability.can :read, Article, :priority.lt => 2
295
+ article1 = Article.create!(:priority => 1)
296
+ article2 = Article.create!(:priority => 3)
297
+ expect(Article.accessible_by(@ability)).to eq([article1])
298
+ expect(@ability).to be_able_to(:read, article1)
299
+ expect(@ability).to_not be_able_to(:read, article2)
300
+ end
301
+
302
+ it "merges MetaWhere and non-MetaWhere conditions" do
303
+ @ability.can :read, Article, :priority.lt => 2
304
+ @ability.can :read, Article, :priority => 1
305
+ article1 = Article.create!(:priority => 1)
306
+ article2 = Article.create!(:priority => 3)
307
+ expect(Article.accessible_by(@ability)).to eq([article1])
308
+ expect(@ability).to be_able_to(:read, article1)
309
+ expect(@ability).to_not be_able_to(:read, article2)
310
+ end
311
+
312
+ it "matches any MetaWhere condition" do
313
+ adapter = CanCan::ModelAdapters::ActiveRecordAdapter
314
+ article1 = Article.new(:priority => 1, :name => "Hello World")
315
+ expect(adapter.matches_condition?(article1, :priority.eq, 1)).to be_true
316
+ expect(adapter.matches_condition?(article1, :priority.eq, 2)).to be_false
317
+ expect(adapter.matches_condition?(article1, :priority.eq_any, [1, 2])).to be_true
318
+ expect(adapter.matches_condition?(article1, :priority.eq_any, [2, 3])).to be_false
319
+ expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 1])).to be_true
320
+ expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 2])).to be_false
321
+ expect(adapter.matches_condition?(article1, :priority.ne, 2)).to be_true
322
+ expect(adapter.matches_condition?(article1, :priority.ne, 1)).to be_false
323
+ expect(adapter.matches_condition?(article1, :priority.in, [1, 2])).to be_true
324
+ expect(adapter.matches_condition?(article1, :priority.in, [2, 3])).to be_false
325
+ expect(adapter.matches_condition?(article1, :priority.nin, [2, 3])).to be_true
326
+ expect(adapter.matches_condition?(article1, :priority.nin, [1, 2])).to be_false
327
+ expect(adapter.matches_condition?(article1, :priority.lt, 2)).to be_true
328
+ expect(adapter.matches_condition?(article1, :priority.lt, 1)).to be_false
329
+ expect(adapter.matches_condition?(article1, :priority.lteq, 1)).to be_true
330
+ expect(adapter.matches_condition?(article1, :priority.lteq, 0)).to be_false
331
+ expect(adapter.matches_condition?(article1, :priority.gt, 0)).to be_true
332
+ expect(adapter.matches_condition?(article1, :priority.gt, 1)).to be_false
333
+ expect(adapter.matches_condition?(article1, :priority.gteq, 1)).to be_true
334
+ expect(adapter.matches_condition?(article1, :priority.gteq, 2)).to be_false
335
+ expect(adapter.matches_condition?(article1, :name.like, "%ello worl%")).to be_true
336
+ expect(adapter.matches_condition?(article1, :name.like, "hello world")).to be_true
337
+ expect(adapter.matches_condition?(article1, :name.like, "hello%")).to be_true
338
+ expect(adapter.matches_condition?(article1, :name.like, "h%d")).to be_true
339
+ expect(adapter.matches_condition?(article1, :name.like, "%helo%")).to be_false
340
+ expect(adapter.matches_condition?(article1, :name.like, "hello")).to be_false
341
+ expect(adapter.matches_condition?(article1, :name.like, "hello.world")).to be_false
342
+ # For some reason this is reporting "The not_matches MetaWhere condition is not supported."
343
+ # expect(adapter.matches_condition?(article1, :name.nlike, "%helo%")).to be_true
344
+ # expect(adapter.matches_condition?(article1, :name.nlike, "%ello worl%")).to be_false
345
+ end
346
+
347
+ it 'should not execute a scope when checking ability on the class' do
348
+ relation = Article.where(:secret => true)
349
+ @ability.can :read, Article, relation do |article|
350
+ article.secret == true
351
+ end
352
+
353
+ relation.stub(:count).and_raise('Unexpected scope execution.')
354
+
355
+ expect { @ability.can? :read, Article }.not_to raise_error
356
+ end
357
+ end
358
+ end