codeprimate-cancan 1.6.5
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.
- data/CHANGELOG.rdoc +291 -0
- data/Gemfile +20 -0
- data/LICENSE +20 -0
- data/README.rdoc +111 -0
- data/Rakefile +18 -0
- data/init.rb +1 -0
- data/lib/cancan.rb +13 -0
- data/lib/cancan/ability.rb +298 -0
- data/lib/cancan/controller_additions.rb +389 -0
- data/lib/cancan/controller_resource.rb +222 -0
- data/lib/cancan/exceptions.rb +50 -0
- data/lib/cancan/inherited_resource.rb +19 -0
- data/lib/cancan/matchers.rb +14 -0
- data/lib/cancan/model_adapters/abstract_adapter.rb +56 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +165 -0
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +34 -0
- data/lib/cancan/model_adapters/default_adapter.rb +7 -0
- data/lib/cancan/model_adapters/mongoid_adapter.rb +53 -0
- data/lib/cancan/model_additions.rb +31 -0
- data/lib/cancan/rule.rb +142 -0
- data/lib/generators/cancan/ability/USAGE +4 -0
- data/lib/generators/cancan/ability/ability_generator.rb +11 -0
- data/lib/generators/cancan/ability/templates/ability.rb +28 -0
- data/spec/README.rdoc +28 -0
- data/spec/cancan/ability_spec.rb +419 -0
- data/spec/cancan/controller_additions_spec.rb +137 -0
- data/spec/cancan/controller_resource_spec.rb +412 -0
- data/spec/cancan/exceptions_spec.rb +58 -0
- data/spec/cancan/inherited_resource_spec.rb +42 -0
- data/spec/cancan/matchers_spec.rb +33 -0
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +278 -0
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +119 -0
- data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +216 -0
- data/spec/cancan/rule_spec.rb +39 -0
- data/spec/matchers.rb +13 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +41 -0
- metadata +167 -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
|