corntrace-cancan 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG.rdoc +291 -0
  2. data/Gemfile +20 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +111 -0
  5. data/Rakefile +18 -0
  6. data/init.rb +1 -0
  7. data/lib/cancan.rb +13 -0
  8. data/lib/cancan/ability.rb +298 -0
  9. data/lib/cancan/controller_additions.rb +389 -0
  10. data/lib/cancan/controller_resource.rb +224 -0
  11. data/lib/cancan/exceptions.rb +50 -0
  12. data/lib/cancan/inherited_resource.rb +19 -0
  13. data/lib/cancan/matchers.rb +14 -0
  14. data/lib/cancan/model_adapters/abstract_adapter.rb +56 -0
  15. data/lib/cancan/model_adapters/active_record_adapter.rb +165 -0
  16. data/lib/cancan/model_adapters/data_mapper_adapter.rb +34 -0
  17. data/lib/cancan/model_adapters/default_adapter.rb +7 -0
  18. data/lib/cancan/model_adapters/mongoid_adapter.rb +53 -0
  19. data/lib/cancan/model_additions.rb +31 -0
  20. data/lib/cancan/rule.rb +142 -0
  21. data/lib/generators/cancan/ability/USAGE +4 -0
  22. data/lib/generators/cancan/ability/ability_generator.rb +11 -0
  23. data/lib/generators/cancan/ability/templates/ability.rb +28 -0
  24. data/spec/README.rdoc +28 -0
  25. data/spec/cancan/ability_spec.rb +419 -0
  26. data/spec/cancan/controller_additions_spec.rb +137 -0
  27. data/spec/cancan/controller_resource_spec.rb +412 -0
  28. data/spec/cancan/exceptions_spec.rb +58 -0
  29. data/spec/cancan/inherited_resource_spec.rb +42 -0
  30. data/spec/cancan/matchers_spec.rb +33 -0
  31. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +278 -0
  32. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +119 -0
  33. data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
  34. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +216 -0
  35. data/spec/cancan/rule_spec.rb +39 -0
  36. data/spec/matchers.rb +13 -0
  37. data/spec/spec.opts +2 -0
  38. data/spec/spec_helper.rb +41 -0
  39. metadata +137 -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 "should have action and subject accessors" do
10
+ @exception.action.should == :some_action
11
+ @exception.subject.should == :some_subject
12
+ end
13
+
14
+ it "should have a changable default message" do
15
+ @exception.message.should == "You are not authorized to access this page."
16
+ @exception.default_message = "Unauthorized!"
17
+ @exception.message.should == "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 "should have nil action and subject" do
27
+ @exception.action.should be_nil
28
+ @exception.subject.should be_nil
29
+ end
30
+
31
+ it "should have passed message" do
32
+ @exception.message.should == "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
+ @exception.message.should == "This is a different message"
45
+ end
46
+
47
+ it "defaults to a nice message" do
48
+ @exception = CanCan::AccessDenied.new
49
+ @exception.message.should == "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
+ @exception.message.should == "Hey! You're not welcome here"
55
+ @exception.message.should_not == "You are not authorized to access this page."
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,42 @@
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
+ stub(@controller).params { @params }
10
+ stub(@controller).current_ability { @ability }
11
+ stub(@controller_class).cancan_skipper { {:authorize => {}, :load => {}} }
12
+ end
13
+
14
+ it "show should load resource through @controller.resource" do
15
+ @params.merge!(:action => "show", :id => 123)
16
+ stub(@controller).resource { :project_resource }
17
+ CanCan::InheritedResource.new(@controller).load_resource
18
+ @controller.instance_variable_get(:@project).should == :project_resource
19
+ end
20
+
21
+ it "new should load through @controller.build_resource" do
22
+ @params[:action] = "new"
23
+ stub(@controller).build_resource { :project_resource }
24
+ CanCan::InheritedResource.new(@controller).load_resource
25
+ @controller.instance_variable_get(:@project).should == :project_resource
26
+ end
27
+
28
+ it "index should load through @controller.association_chain when parent" do
29
+ @params[:action] = "index"
30
+ stub(@controller).association_chain { @controller.instance_variable_set(:@project, :project_resource) }
31
+ CanCan::InheritedResource.new(@controller, :parent => true).load_resource
32
+ @controller.instance_variable_get(:@project).should == :project_resource
33
+ end
34
+
35
+ it "index should load through @controller.end_of_association_chain" do
36
+ @params[:action] = "index"
37
+ stub(Project).accessible_by(@ability, :index) { :projects }
38
+ stub(@controller).end_of_association_chain { Project }
39
+ CanCan::InheritedResource.new(@controller).load_resource
40
+ @controller.instance_variable_get(:@projects).should == :projects
41
+ end
42
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe "be_able_to" do
4
+ it "delegates to can?" do
5
+ object = Object.new
6
+ mock(object).can?(:read, 123) { true }
7
+ object.should be_able_to(:read, 123)
8
+ end
9
+
10
+ it "reports a nice failure message for should" do
11
+ object = Object.new
12
+ mock(object).can?(:read, 123) { false }
13
+ expect do
14
+ object.should be_able_to(:read, 123)
15
+ end.should raise_error('expected to be able to :read 123')
16
+ end
17
+
18
+ it "reports a nice failure message for should not" do
19
+ object = Object.new
20
+ mock(object).can?(:read, 123) { true }
21
+ expect do
22
+ object.should_not be_able_to(:read, 123)
23
+ end.should raise_error('expected not to be able to :read 123')
24
+ end
25
+
26
+ it "delegates additional arguments to can? and reports in failure message" do
27
+ object = Object.new
28
+ mock(object).can?(:read, 123, 456) { false }
29
+ expect do
30
+ object.should be_able_to(:read, 123, 456)
31
+ end.should raise_error('expected to be able to :read 123 456')
32
+ end
33
+ end
@@ -0,0 +1,278 @@
1
+ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
2
+ require "spec_helper"
3
+
4
+ RSpec.configure do |config|
5
+ config.extend WithModel
6
+ end
7
+
8
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
9
+
10
+ describe CanCan::ModelAdapters::ActiveRecordAdapter do
11
+ with_model :category do
12
+ table do |t|
13
+ t.boolean "visible"
14
+ end
15
+ model do
16
+ has_many :articles
17
+ end
18
+ end
19
+
20
+ with_model :article do
21
+ table do |t|
22
+ t.string "name"
23
+ t.boolean "published"
24
+ t.boolean "secret"
25
+ t.integer "priority"
26
+ t.integer "category_id"
27
+ end
28
+ model do
29
+ belongs_to :category
30
+ has_many :comments
31
+ end
32
+ end
33
+
34
+ with_model :comment do
35
+ table do |t|
36
+ t.boolean "spam"
37
+ t.integer "article_id"
38
+ end
39
+ model do
40
+ belongs_to :article
41
+ end
42
+ end
43
+
44
+ before(:each) do
45
+ Article.delete_all
46
+ Comment.delete_all
47
+ @ability = Object.new
48
+ @ability.extend(CanCan::Ability)
49
+ @article_table = Article.table_name
50
+ @comment_table = Comment.table_name
51
+ end
52
+
53
+ it "should be for only active record classes" do
54
+ CanCan::ModelAdapters::ActiveRecordAdapter.should_not be_for_class(Object)
55
+ CanCan::ModelAdapters::ActiveRecordAdapter.should be_for_class(Article)
56
+ CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::ActiveRecordAdapter
57
+ end
58
+
59
+ it "should find record" do
60
+ article = Article.create!
61
+ CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id).should == article
62
+ end
63
+
64
+ it "should not fetch any records when no abilities are defined" do
65
+ Article.create!
66
+ Article.accessible_by(@ability).should be_empty
67
+ end
68
+
69
+ it "should fetch all articles when one can read all" do
70
+ @ability.can :read, Article
71
+ article = Article.create!
72
+ Article.accessible_by(@ability).should == [article]
73
+ end
74
+
75
+ it "should fetch only the articles that are published" do
76
+ @ability.can :read, Article, :published => true
77
+ article1 = Article.create!(:published => true)
78
+ article2 = Article.create!(:published => false)
79
+ Article.accessible_by(@ability).should == [article1]
80
+ end
81
+
82
+ it "should fetch any articles which are published or secret" do
83
+ @ability.can :read, Article, :published => true
84
+ @ability.can :read, Article, :secret => true
85
+ article1 = Article.create!(:published => true, :secret => false)
86
+ article2 = Article.create!(:published => true, :secret => true)
87
+ article3 = Article.create!(:published => false, :secret => true)
88
+ article4 = Article.create!(:published => false, :secret => false)
89
+ Article.accessible_by(@ability).should == [article1, article2, article3]
90
+ end
91
+
92
+ it "should fetch only the articles that are published and not secret" do
93
+ @ability.can :read, Article, :published => true
94
+ @ability.cannot :read, Article, :secret => true
95
+ article1 = Article.create!(:published => true, :secret => false)
96
+ article2 = Article.create!(:published => true, :secret => true)
97
+ article3 = Article.create!(:published => false, :secret => true)
98
+ article4 = Article.create!(:published => false, :secret => false)
99
+ Article.accessible_by(@ability).should == [article1]
100
+ end
101
+
102
+ it "should only read comments for articles which are published" do
103
+ @ability.can :read, Comment, :article => { :published => true }
104
+ comment1 = Comment.create!(:article => Article.create!(:published => true))
105
+ comment2 = Comment.create!(:article => Article.create!(:published => false))
106
+ Comment.accessible_by(@ability).should == [comment1]
107
+ end
108
+
109
+ it "should only read comments for visible categories through articles" do
110
+ @ability.can :read, Comment, :article => { :category => { :visible => true } }
111
+ comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true)))
112
+ comment2 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => false)))
113
+ Comment.accessible_by(@ability).should == [comment1]
114
+ end
115
+
116
+ it "should allow conditions in SQL and merge with hash conditions" do
117
+ @ability.can :read, Article, :published => true
118
+ @ability.can :read, Article, ["secret=?", true]
119
+ article1 = Article.create!(:published => true, :secret => false)
120
+ article2 = Article.create!(:published => true, :secret => true)
121
+ article3 = Article.create!(:published => false, :secret => true)
122
+ article4 = Article.create!(:published => false, :secret => false)
123
+ Article.accessible_by(@ability).should == [article1, article2, article3]
124
+ end
125
+
126
+ it "should allow a scope for conditions" do
127
+ @ability.can :read, Article, Article.where(:secret => true)
128
+ article1 = Article.create!(:secret => true)
129
+ article2 = Article.create!(:secret => false)
130
+ Article.accessible_by(@ability).should == [article1]
131
+ end
132
+
133
+ it "should fetch only associated records when using with a scope for conditions" do
134
+ @ability.can :read, Article, Article.where(:secret => true)
135
+ category1 = Category.create!(:visible => false)
136
+ category2 = Category.create!(:visible => true)
137
+ article1 = Article.create!(:secret => true, :category => category1)
138
+ article2 = Article.create!(:secret => true, :category => category2)
139
+ category1.articles.accessible_by(@ability).should == [article1]
140
+ end
141
+
142
+ it "should raise an exception when trying to merge scope with other conditions" do
143
+ @ability.can :read, Article, :published => true
144
+ @ability.can :read, Article, Article.where(:secret => true)
145
+ lambda { Article.accessible_by(@ability) }.should raise_error(CanCan::Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Article ability.")
146
+ end
147
+
148
+ it "should not allow to fetch records when ability with just block present" do
149
+ @ability.can :read, Article do
150
+ false
151
+ end
152
+ lambda { Article.accessible_by(@ability) }.should raise_error(CanCan::Error)
153
+ end
154
+
155
+ it "should not allow to check ability on object against SQL conditions without block" do
156
+ @ability.can :read, Article, ["secret=?", true]
157
+ lambda { @ability.can? :read, Article.new }.should raise_error(CanCan::Error)
158
+ end
159
+
160
+ it "should have false conditions if no abilities match" do
161
+ @ability.model_adapter(Article, :read).conditions.should == "'t'='f'"
162
+ end
163
+
164
+ it "should return false conditions for cannot clause" do
165
+ @ability.cannot :read, Article
166
+ @ability.model_adapter(Article, :read).conditions.should == "'t'='f'"
167
+ end
168
+
169
+ it "should return SQL for single `can` definition in front of default `cannot` condition" do
170
+ @ability.cannot :read, Article
171
+ @ability.can :read, Article, :published => false, :secret => true
172
+ @ability.model_adapter(Article, :read).conditions.should orderlessly_match(%Q["#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't'])
173
+ end
174
+
175
+ it "should return true condition for single `can` definition in front of default `can` condition" do
176
+ @ability.can :read, Article
177
+ @ability.can :read, Article, :published => false, :secret => true
178
+ @ability.model_adapter(Article, :read).conditions.should == "'t'='t'"
179
+ end
180
+
181
+ it "should return `false condition` for single `cannot` definition in front of default `cannot` condition" do
182
+ @ability.cannot :read, Article
183
+ @ability.cannot :read, Article, :published => false, :secret => true
184
+ @ability.model_adapter(Article, :read).conditions.should == "'t'='f'"
185
+ end
186
+
187
+ it "should return `not (sql)` for single `cannot` definition in front of default `can` condition" do
188
+ @ability.can :read, Article
189
+ @ability.cannot :read, Article, :published => false, :secret => true
190
+ @ability.model_adapter(Article, :read).conditions.should orderlessly_match(%Q["not (#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't')])
191
+ end
192
+
193
+ it "should return appropriate sql conditions in complex case" do
194
+ @ability.can :read, Article
195
+ @ability.can :manage, Article, :id => 1
196
+ @ability.can :update, Article, :published => true
197
+ @ability.cannot :update, Article, :secret => true
198
+ @ability.model_adapter(Article, :update).conditions.should == %Q[not ("#{@article_table}"."secret" = 't') AND (("#{@article_table}"."published" = 't') OR ("#{@article_table}"."id" = 1))]
199
+ @ability.model_adapter(Article, :manage).conditions.should == {:id => 1}
200
+ @ability.model_adapter(Article, :read).conditions.should == "'t'='t'"
201
+ end
202
+
203
+ it "should not forget conditions when calling with SQL string" do
204
+ @ability.can :read, Article, :published => true
205
+ @ability.can :read, Article, ['secret=?', false]
206
+ adapter = @ability.model_adapter(Article, :read)
207
+ 2.times do
208
+ adapter.conditions.should == %Q[(secret='f') OR ("#{@article_table}"."published" = 't')]
209
+ end
210
+ end
211
+
212
+ it "should have nil joins if no rules" do
213
+ @ability.model_adapter(Article, :read).joins.should be_nil
214
+ end
215
+
216
+ it "should have nil joins if no nested hashes specified in conditions" do
217
+ @ability.can :read, Article, :published => false
218
+ @ability.can :read, Article, :secret => true
219
+ @ability.model_adapter(Article, :read).joins.should be_nil
220
+ end
221
+
222
+ it "should merge separate joins into a single array" do
223
+ @ability.can :read, Article, :project => { :blocked => false }
224
+ @ability.can :read, Article, :company => { :admin => true }
225
+ @ability.model_adapter(Article, :read).joins.inspect.should orderlessly_match([:company, :project].inspect)
226
+ end
227
+
228
+ it "should merge same joins into a single array" do
229
+ @ability.can :read, Article, :project => { :blocked => false }
230
+ @ability.can :read, Article, :project => { :admin => true }
231
+ @ability.model_adapter(Article, :read).joins.should == [:project]
232
+ end
233
+
234
+ it "should restrict articles given a MetaWhere condition" do
235
+ @ability.can :read, Article, :priority.lt => 2
236
+ article1 = Article.create!(:priority => 1)
237
+ article2 = Article.create!(:priority => 3)
238
+ Article.accessible_by(@ability).should == [article1]
239
+ @ability.should be_able_to(:read, article1)
240
+ @ability.should_not be_able_to(:read, article2)
241
+ end
242
+
243
+ it "should match any MetaWhere condition" do
244
+ adapter = CanCan::ModelAdapters::ActiveRecordAdapter
245
+ article1 = Article.new(:priority => 1, :name => "Hello World")
246
+ adapter.matches_condition?(article1, :priority.eq, 1).should be_true
247
+ adapter.matches_condition?(article1, :priority.eq, 2).should be_false
248
+ adapter.matches_condition?(article1, :priority.eq_any, [1, 2]).should be_true
249
+ adapter.matches_condition?(article1, :priority.eq_any, [2, 3]).should be_false
250
+ adapter.matches_condition?(article1, :priority.eq_all, [1, 1]).should be_true
251
+ adapter.matches_condition?(article1, :priority.eq_all, [1, 2]).should be_false
252
+ adapter.matches_condition?(article1, :priority.ne, 2).should be_true
253
+ adapter.matches_condition?(article1, :priority.ne, 1).should be_false
254
+ adapter.matches_condition?(article1, :priority.in, [1, 2]).should be_true
255
+ adapter.matches_condition?(article1, :priority.in, [2, 3]).should be_false
256
+ adapter.matches_condition?(article1, :priority.nin, [2, 3]).should be_true
257
+ adapter.matches_condition?(article1, :priority.nin, [1, 2]).should be_false
258
+ adapter.matches_condition?(article1, :priority.lt, 2).should be_true
259
+ adapter.matches_condition?(article1, :priority.lt, 1).should be_false
260
+ adapter.matches_condition?(article1, :priority.lteq, 1).should be_true
261
+ adapter.matches_condition?(article1, :priority.lteq, 0).should be_false
262
+ adapter.matches_condition?(article1, :priority.gt, 0).should be_true
263
+ adapter.matches_condition?(article1, :priority.gt, 1).should be_false
264
+ adapter.matches_condition?(article1, :priority.gteq, 1).should be_true
265
+ adapter.matches_condition?(article1, :priority.gteq, 2).should be_false
266
+ adapter.matches_condition?(article1, :name.like, "%ello worl%").should be_true
267
+ adapter.matches_condition?(article1, :name.like, "hello world").should be_true
268
+ adapter.matches_condition?(article1, :name.like, "hello%").should be_true
269
+ adapter.matches_condition?(article1, :name.like, "h%d").should be_true
270
+ adapter.matches_condition?(article1, :name.like, "%helo%").should be_false
271
+ adapter.matches_condition?(article1, :name.like, "hello").should be_false
272
+ adapter.matches_condition?(article1, :name.like, "hello.world").should be_false
273
+ # For some reason this is reporting "The not_matches MetaWhere condition is not supported."
274
+ # adapter.matches_condition?(article1, :name.nlike, "%helo%").should be_true
275
+ # adapter.matches_condition?(article1, :name.nlike, "%ello worl%").should be_false
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,119 @@
1
+ if ENV["MODEL_ADAPTER"] == "data_mapper"
2
+ require "spec_helper"
3
+
4
+ DataMapper.setup(:default, 'sqlite::memory:')
5
+
6
+ class Article
7
+ include DataMapper::Resource
8
+ property :id, Serial
9
+ property :published, Boolean, :default => false
10
+ property :secret, Boolean, :default => false
11
+ property :priority, Integer
12
+ has n, :comments
13
+ end
14
+
15
+ class Comment
16
+ include DataMapper::Resource
17
+ property :id, Serial
18
+ property :spam, Boolean, :default => false
19
+ belongs_to :article
20
+ end
21
+
22
+ DataMapper.finalize
23
+ DataMapper.auto_migrate!
24
+
25
+ describe CanCan::ModelAdapters::DataMapperAdapter do
26
+ before(:each) do
27
+ Article.destroy
28
+ Comment.destroy
29
+ @ability = Object.new
30
+ @ability.extend(CanCan::Ability)
31
+ end
32
+
33
+ it "should be for only data mapper classes" do
34
+ CanCan::ModelAdapters::DataMapperAdapter.should_not be_for_class(Object)
35
+ CanCan::ModelAdapters::DataMapperAdapter.should be_for_class(Article)
36
+ CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::DataMapperAdapter
37
+ end
38
+
39
+ it "should find record" do
40
+ article = Article.create
41
+ CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id).should == article
42
+ end
43
+
44
+ it "should not fetch any records when no abilities are defined" do
45
+ Article.create
46
+ Article.accessible_by(@ability).should be_empty
47
+ end
48
+
49
+ it "should fetch all articles when one can read all" do
50
+ @ability.can :read, Article
51
+ article = Article.create
52
+ Article.accessible_by(@ability).should == [article]
53
+ end
54
+
55
+ it "should fetch only the articles that are published" do
56
+ @ability.can :read, Article, :published => true
57
+ article1 = Article.create(:published => true)
58
+ article2 = Article.create(:published => false)
59
+ Article.accessible_by(@ability).should == [article1]
60
+ end
61
+
62
+ it "should fetch any articles which are published or secret" do
63
+ @ability.can :read, Article, :published => true
64
+ @ability.can :read, Article, :secret => true
65
+ article1 = Article.create(:published => true, :secret => false)
66
+ article2 = Article.create(:published => true, :secret => true)
67
+ article3 = Article.create(:published => false, :secret => true)
68
+ article4 = Article.create(:published => false, :secret => false)
69
+ Article.accessible_by(@ability).should == [article1, article2, article3]
70
+ end
71
+
72
+ it "should fetch only the articles that are published and not secret" do
73
+ @ability.can :read, Article, :published => true
74
+ @ability.cannot :read, Article, :secret => true
75
+ article1 = Article.create(:published => true, :secret => false)
76
+ article2 = Article.create(:published => true, :secret => true)
77
+ article3 = Article.create(:published => false, :secret => true)
78
+ article4 = Article.create(:published => false, :secret => false)
79
+ Article.accessible_by(@ability).should == [article1]
80
+ end
81
+
82
+ it "should only read comments for articles which are published" do
83
+ @ability.can :read, Comment, :article => { :published => true }
84
+ comment1 = Comment.create(:article => Article.create!(:published => true))
85
+ comment2 = Comment.create(:article => Article.create!(:published => false))
86
+ Comment.accessible_by(@ability).should == [comment1]
87
+ end
88
+
89
+ it "should allow conditions in SQL and merge with hash conditions" do
90
+ @ability.can :read, Article, :published => true
91
+ @ability.can :read, Article, ["secret=?", true]
92
+ article1 = Article.create(:published => true, :secret => false)
93
+ article4 = Article.create(:published => false, :secret => false)
94
+ Article.accessible_by(@ability).should == [article1]
95
+ end
96
+
97
+ it "should match gt comparison" do
98
+ @ability.can :read, Article, :priority.gt => 3
99
+ article1 = Article.create(:priority => 4)
100
+ article2 = Article.create(:priority => 3)
101
+ Article.accessible_by(@ability).should == [article1]
102
+ @ability.should be_able_to(:read, article1)
103
+ @ability.should_not be_able_to(:read, article2)
104
+ end
105
+
106
+ it "should match gte comparison" do
107
+ @ability.can :read, Article, :priority.gte => 3
108
+ article1 = Article.create(:priority => 4)
109
+ article2 = Article.create(:priority => 3)
110
+ article3 = Article.create(:priority => 2)
111
+ Article.accessible_by(@ability).should == [article1, article2]
112
+ @ability.should be_able_to(:read, article1)
113
+ @ability.should be_able_to(:read, article2)
114
+ @ability.should_not be_able_to(:read, article3)
115
+ end
116
+
117
+ # TODO: add more comparison specs
118
+ end
119
+ end