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.
- checksums.yaml +15 -0
- data/CHANGELOG.rdoc +427 -0
- data/CONTRIBUTING.md +11 -0
- data/Gemfile +23 -0
- data/LICENSE +20 -0
- data/README.rdoc +161 -0
- data/Rakefile +18 -0
- data/init.rb +1 -0
- data/lib/cancan.rb +13 -0
- data/lib/cancan/ability.rb +324 -0
- data/lib/cancan/controller_additions.rb +397 -0
- data/lib/cancan/controller_resource.rb +286 -0
- data/lib/cancan/exceptions.rb +50 -0
- data/lib/cancan/inherited_resource.rb +20 -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 +180 -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 +54 -0
- data/lib/cancan/model_additions.rb +31 -0
- data/lib/cancan/rule.rb +147 -0
- data/lib/cancancan.rb +1 -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 +32 -0
- data/spec/README.rdoc +28 -0
- data/spec/cancan/ability_spec.rb +455 -0
- data/spec/cancan/controller_additions_spec.rb +141 -0
- data/spec/cancan/controller_resource_spec.rb +553 -0
- data/spec/cancan/exceptions_spec.rb +58 -0
- data/spec/cancan/inherited_resource_spec.rb +60 -0
- data/spec/cancan/matchers_spec.rb +29 -0
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +358 -0
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +118 -0
- data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +226 -0
- data/spec/cancan/rule_spec.rb +52 -0
- data/spec/matchers.rb +13 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +77 -0
- metadata +126 -0
@@ -0,0 +1,118 @@
|
|
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 = double).extend(CanCan::Ability)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "is for only data mapper classes" do
|
33
|
+
expect(CanCan::ModelAdapters::DataMapperAdapter).not_to be_for_class(Object)
|
34
|
+
expect(CanCan::ModelAdapters::DataMapperAdapter).to be_for_class(Article)
|
35
|
+
expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::DataMapperAdapter)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "finds record" do
|
39
|
+
article = Article.create
|
40
|
+
expect(CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id)).to eq(article)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "does not fetch any records when no abilities are defined" do
|
44
|
+
Article.create
|
45
|
+
expect(Article.accessible_by(@ability)).to be_empty
|
46
|
+
end
|
47
|
+
|
48
|
+
it "fetches all articles when one can read all" do
|
49
|
+
@ability.can :read, Article
|
50
|
+
article = Article.create
|
51
|
+
expect(Article.accessible_by(@ability)).to eq([article])
|
52
|
+
end
|
53
|
+
|
54
|
+
it "fetches only the articles that are published" do
|
55
|
+
@ability.can :read, Article, :published => true
|
56
|
+
article1 = Article.create(:published => true)
|
57
|
+
article2 = Article.create(:published => false)
|
58
|
+
expect(Article.accessible_by(@ability)).to eq([article1])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "fetches any articles which are published or secret" do
|
62
|
+
@ability.can :read, Article, :published => true
|
63
|
+
@ability.can :read, Article, :secret => true
|
64
|
+
article1 = Article.create(:published => true, :secret => false)
|
65
|
+
article2 = Article.create(:published => true, :secret => true)
|
66
|
+
article3 = Article.create(:published => false, :secret => true)
|
67
|
+
article4 = Article.create(:published => false, :secret => false)
|
68
|
+
expect(Article.accessible_by(@ability)).to eq([article1, article2, article3])
|
69
|
+
end
|
70
|
+
|
71
|
+
it "fetches only the articles that are published and not secret" do
|
72
|
+
@ability.can :read, Article, :published => true
|
73
|
+
@ability.cannot :read, Article, :secret => true
|
74
|
+
article1 = Article.create(:published => true, :secret => false)
|
75
|
+
article2 = Article.create(:published => true, :secret => true)
|
76
|
+
article3 = Article.create(:published => false, :secret => true)
|
77
|
+
article4 = Article.create(:published => false, :secret => false)
|
78
|
+
expect(Article.accessible_by(@ability)).to eq([article1])
|
79
|
+
end
|
80
|
+
|
81
|
+
it "only reads comments for articles which are published" do
|
82
|
+
@ability.can :read, Comment, :article => { :published => true }
|
83
|
+
comment1 = Comment.create(:article => Article.create!(:published => true))
|
84
|
+
comment2 = Comment.create(:article => Article.create!(:published => false))
|
85
|
+
expect(Comment.accessible_by(@ability)).to eq([comment1])
|
86
|
+
end
|
87
|
+
|
88
|
+
it "allows conditions in SQL and merge with hash conditions" do
|
89
|
+
@ability.can :read, Article, :published => true
|
90
|
+
@ability.can :read, Article, ["secret=?", true]
|
91
|
+
article1 = Article.create(:published => true, :secret => false)
|
92
|
+
article4 = Article.create(:published => false, :secret => false)
|
93
|
+
expect(Article.accessible_by(@ability)).to eq([article1])
|
94
|
+
end
|
95
|
+
|
96
|
+
it "matches gt comparison" do
|
97
|
+
@ability.can :read, Article, :priority.gt => 3
|
98
|
+
article1 = Article.create(:priority => 4)
|
99
|
+
article2 = Article.create(:priority => 3)
|
100
|
+
expect(Article.accessible_by(@ability)).to eq([article1])
|
101
|
+
expect(@ability).to be_able_to(:read, article1)
|
102
|
+
expect(@ability).not_to be_able_to(:read, article2)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "matches gte comparison" do
|
106
|
+
@ability.can :read, Article, :priority.gte => 3
|
107
|
+
article1 = Article.create(:priority => 4)
|
108
|
+
article2 = Article.create(:priority => 3)
|
109
|
+
article3 = Article.create(:priority => 2)
|
110
|
+
expect(Article.accessible_by(@ability)).to eq([article1, article2])
|
111
|
+
expect(@ability).to be_able_to(:read, article1)
|
112
|
+
expect(@ability).to be_able_to(:read, article2)
|
113
|
+
expect(@ability).not_to be_able_to(:read, article3)
|
114
|
+
end
|
115
|
+
|
116
|
+
# TODO: add more comparison specs
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
if ENV["MODEL_ADAPTER"] == "mongoid"
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
class MongoidCategory
|
5
|
+
include Mongoid::Document
|
6
|
+
|
7
|
+
references_many :mongoid_projects
|
8
|
+
end
|
9
|
+
|
10
|
+
class MongoidProject
|
11
|
+
include Mongoid::Document
|
12
|
+
|
13
|
+
referenced_in :mongoid_category
|
14
|
+
end
|
15
|
+
|
16
|
+
Mongoid.configure do |config|
|
17
|
+
config.master = Mongo::Connection.new('127.0.0.1', 27017).db("cancan_mongoid_spec")
|
18
|
+
end
|
19
|
+
|
20
|
+
describe CanCan::ModelAdapters::MongoidAdapter do
|
21
|
+
context "Mongoid defined" do
|
22
|
+
before(:each) do
|
23
|
+
(@ability = double).extend(CanCan::Ability)
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:each) do
|
27
|
+
Mongoid.master.collections.select do |collection|
|
28
|
+
collection.name !~ /system/
|
29
|
+
end.each(&:drop)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "is for only Mongoid classes" do
|
33
|
+
expect(CanCan::ModelAdapters::MongoidAdapter).not_to be_for_class(Object)
|
34
|
+
expect(CanCan::ModelAdapters::MongoidAdapter).to be_for_class(MongoidProject)
|
35
|
+
expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject)).to eq(CanCan::ModelAdapters::MongoidAdapter)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "finds record" do
|
39
|
+
project = MongoidProject.create
|
40
|
+
expect(CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id)).to eq(project)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "compares properties on mongoid documents with the conditions hash" do
|
44
|
+
model = MongoidProject.new
|
45
|
+
@ability.can :read, MongoidProject, :id => model.id
|
46
|
+
expect(@ability).to be_able_to(:read, model)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "is able to read hashes when field is array" do
|
50
|
+
one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three'])
|
51
|
+
two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five'])
|
52
|
+
|
53
|
+
@ability.can :foo, MongoidProject, :numbers => 'one'
|
54
|
+
expect(@ability).to be_able_to(:foo, one_to_three)
|
55
|
+
expect(@ability).not_to be_able_to(:foo, two_to_five)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns [] when no ability is defined so no records are found" do
|
59
|
+
MongoidProject.create(:title => 'Sir')
|
60
|
+
MongoidProject.create(:title => 'Lord')
|
61
|
+
MongoidProject.create(:title => 'Dude')
|
62
|
+
|
63
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([])
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns the correct records based on the defined ability" do
|
67
|
+
@ability.can :read, MongoidProject, :title => "Sir"
|
68
|
+
sir = MongoidProject.create(:title => 'Sir')
|
69
|
+
lord = MongoidProject.create(:title => 'Lord')
|
70
|
+
dude = MongoidProject.create(:title => 'Dude')
|
71
|
+
|
72
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir])
|
73
|
+
end
|
74
|
+
|
75
|
+
it "returns the correct records when a mix of can and cannot rules in defined ability" do
|
76
|
+
@ability.can :manage, MongoidProject, :title => 'Sir'
|
77
|
+
@ability.cannot :destroy, MongoidProject
|
78
|
+
|
79
|
+
sir = MongoidProject.create(:title => 'Sir')
|
80
|
+
lord = MongoidProject.create(:title => 'Lord')
|
81
|
+
dude = MongoidProject.create(:title => 'Dude')
|
82
|
+
|
83
|
+
expect(MongoidProject.accessible_by(@ability, :destroy).entries).to eq([sir])
|
84
|
+
end
|
85
|
+
|
86
|
+
it "is able to mix empty conditions and hashes" do
|
87
|
+
@ability.can :read, MongoidProject
|
88
|
+
@ability.can :read, MongoidProject, :title => 'Sir'
|
89
|
+
sir = MongoidProject.create(:title => 'Sir')
|
90
|
+
lord = MongoidProject.create(:title => 'Lord')
|
91
|
+
|
92
|
+
expect(MongoidProject.accessible_by(@ability, :read).count).to eq(2)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns everything when the defined ability is access all" do
|
96
|
+
@ability.can :manage, :all
|
97
|
+
sir = MongoidProject.create(:title => 'Sir')
|
98
|
+
lord = MongoidProject.create(:title => 'Lord')
|
99
|
+
dude = MongoidProject.create(:title => 'Dude')
|
100
|
+
|
101
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir, lord, dude])
|
102
|
+
end
|
103
|
+
|
104
|
+
it "allows a scope for conditions" do
|
105
|
+
@ability.can :read, MongoidProject, MongoidProject.where(:title => 'Sir')
|
106
|
+
sir = MongoidProject.create(:title => 'Sir')
|
107
|
+
lord = MongoidProject.create(:title => 'Lord')
|
108
|
+
dude = MongoidProject.create(:title => 'Dude')
|
109
|
+
|
110
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir])
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
|
114
|
+
it "handles :field.in" do
|
115
|
+
obj = MongoidProject.create(:title => 'Sir')
|
116
|
+
@ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"]
|
117
|
+
expect(@ability.can?(:read, obj)).to eq(true)
|
118
|
+
expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
|
119
|
+
|
120
|
+
obj2 = MongoidProject.create(:title => 'Lord')
|
121
|
+
expect(@ability.can?(:read, obj2)).to be_false
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "activates only when there are Criteria in the hash" do
|
125
|
+
it "Calls where on the model class when there are criteria" do
|
126
|
+
obj = MongoidProject.create(:title => 'Bird')
|
127
|
+
@conditions = {:title.nin => ["Fork", "Spoon"]}
|
128
|
+
|
129
|
+
@ability.can :read, MongoidProject, @conditions
|
130
|
+
expect(@ability).to be_able_to(:read, obj)
|
131
|
+
end
|
132
|
+
it "Calls the base version if there are no mongoid criteria" do
|
133
|
+
obj = MongoidProject.new(:title => 'Bird')
|
134
|
+
@conditions = {:id => obj.id}
|
135
|
+
@ability.can :read, MongoidProject, @conditions
|
136
|
+
expect(@ability).to be_able_to(:read, obj)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "handles :field.nin" do
|
141
|
+
obj = MongoidProject.create(:title => 'Sir')
|
142
|
+
@ability.can :read, MongoidProject, :title.nin => ["Lord", "Madam"]
|
143
|
+
expect(@ability.can?(:read, obj)).to eq(true)
|
144
|
+
expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
|
145
|
+
|
146
|
+
obj2 = MongoidProject.create(:title => 'Lord')
|
147
|
+
expect(@ability.can?(:read, obj2)).to be_false
|
148
|
+
end
|
149
|
+
|
150
|
+
it "handles :field.size" do
|
151
|
+
obj = MongoidProject.create(:titles => ['Palatin', 'Margrave'])
|
152
|
+
@ability.can :read, MongoidProject, :titles.size => 2
|
153
|
+
expect(@ability.can?(:read, obj)).to eq(true)
|
154
|
+
expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
|
155
|
+
|
156
|
+
obj2 = MongoidProject.create(:titles => ['Palatin', 'Margrave', 'Marquis'])
|
157
|
+
expect(@ability.can?(:read, obj2)).to be_false
|
158
|
+
end
|
159
|
+
|
160
|
+
it "handles :field.exists" do
|
161
|
+
obj = MongoidProject.create(:titles => ['Palatin', 'Margrave'])
|
162
|
+
@ability.can :read, MongoidProject, :titles.exists => true
|
163
|
+
expect(@ability.can?(:read, obj)).to eq(true)
|
164
|
+
expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
|
165
|
+
|
166
|
+
obj2 = MongoidProject.create
|
167
|
+
expect(@ability.can?(:read, obj2)).to be_false
|
168
|
+
end
|
169
|
+
|
170
|
+
it "handles :field.gt" do
|
171
|
+
obj = MongoidProject.create(:age => 50)
|
172
|
+
@ability.can :read, MongoidProject, :age.gt => 45
|
173
|
+
expect(@ability.can?(:read, obj)).to eq(true)
|
174
|
+
expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj])
|
175
|
+
|
176
|
+
obj2 = MongoidProject.create(:age => 40)
|
177
|
+
expect(@ability.can?(:read, obj2)).to be_false
|
178
|
+
end
|
179
|
+
|
180
|
+
it "handles instance not saved to database" do
|
181
|
+
obj = MongoidProject.new(:title => 'Sir')
|
182
|
+
@ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"]
|
183
|
+
expect(@ability.can?(:read, obj)).to eq(true)
|
184
|
+
|
185
|
+
# accessible_by only returns saved records
|
186
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([])
|
187
|
+
|
188
|
+
obj2 = MongoidProject.new(:title => 'Lord')
|
189
|
+
expect(@ability.can?(:read, obj2)).to be_false
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
it "calls where with matching ability conditions" do
|
194
|
+
obj = MongoidProject.create(:foo => {:bar => 1})
|
195
|
+
@ability.can :read, MongoidProject, :foo => {:bar => 1}
|
196
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries.first).to eq(obj)
|
197
|
+
end
|
198
|
+
|
199
|
+
it "excludes from the result if set to cannot" do
|
200
|
+
obj = MongoidProject.create(:bar => 1)
|
201
|
+
obj2 = MongoidProject.create(:bar => 2)
|
202
|
+
@ability.can :read, MongoidProject
|
203
|
+
@ability.cannot :read, MongoidProject, :bar => 2
|
204
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([obj])
|
205
|
+
end
|
206
|
+
|
207
|
+
it "combines the rules" do
|
208
|
+
obj = MongoidProject.create(:bar => 1)
|
209
|
+
obj2 = MongoidProject.create(:bar => 2)
|
210
|
+
obj3 = MongoidProject.create(:bar => 3)
|
211
|
+
@ability.can :read, MongoidProject, :bar => 1
|
212
|
+
@ability.can :read, MongoidProject, :bar => 2
|
213
|
+
expect(MongoidProject.accessible_by(@ability, :read).entries).to match_array([obj, obj2])
|
214
|
+
end
|
215
|
+
|
216
|
+
it "does not allow to fetch records when ability with just block present" do
|
217
|
+
@ability.can :read, MongoidProject do
|
218
|
+
false
|
219
|
+
end
|
220
|
+
expect {
|
221
|
+
MongoidProject.accessible_by(@ability)
|
222
|
+
}.to raise_error(CanCan::Error)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "ostruct" # for OpenStruct below
|
3
|
+
|
4
|
+
# Most of Rule functionality is tested in Ability specs
|
5
|
+
describe CanCan::Rule do
|
6
|
+
before(:each) do
|
7
|
+
@conditions = {}
|
8
|
+
@rule = CanCan::Rule.new(true, :read, Integer, @conditions, nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns no association joins if none exist" do
|
12
|
+
expect(@rule.associations_hash).to eq({})
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns no association for joins if just attributes" do
|
16
|
+
@conditions[:foo] = :bar
|
17
|
+
expect(@rule.associations_hash).to eq({})
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns single association for joins" do
|
21
|
+
@conditions[:foo] = {:bar => 1}
|
22
|
+
expect(@rule.associations_hash).to eq({:foo => {}})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns multiple associations for joins" do
|
26
|
+
@conditions[:foo] = {:bar => 1}
|
27
|
+
@conditions[:test] = {1 => 2}
|
28
|
+
expect(@rule.associations_hash).to eq({:foo => {}, :test => {}})
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns nested associations for joins" do
|
32
|
+
@conditions[:foo] = {:bar => {1 => 2}}
|
33
|
+
expect(@rule.associations_hash).to eq({:foo => {:bar => {}}})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns no association joins if conditions is nil" do
|
37
|
+
rule = CanCan::Rule.new(true, :read, Integer, nil, nil)
|
38
|
+
expect(rule.associations_hash).to eq({})
|
39
|
+
end
|
40
|
+
|
41
|
+
it "is not mergeable if conditions are not simple hashes" do
|
42
|
+
meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test')
|
43
|
+
@conditions[meta_where] = :bar
|
44
|
+
|
45
|
+
expect(@rule).to be_unmergeable
|
46
|
+
end
|
47
|
+
|
48
|
+
it "is not mergeable if conditions is an empty hash" do
|
49
|
+
@conditions = {}
|
50
|
+
expect(@rule).to_not be_unmergeable
|
51
|
+
end
|
52
|
+
end
|
data/spec/matchers.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
RSpec::Matchers.define :orderlessly_match do |original_string|
|
2
|
+
match do |given_string|
|
3
|
+
original_string.split('').sort == given_string.split('').sort
|
4
|
+
end
|
5
|
+
|
6
|
+
failure_message_for_should do |given_string|
|
7
|
+
"expected \"#{given_string}\" to have the same characters as \"#{original_string}\""
|
8
|
+
end
|
9
|
+
|
10
|
+
failure_message_for_should_not do |given_string|
|
11
|
+
"expected \"#{given_string}\" not to have the same characters as \"#{original_string}\""
|
12
|
+
end
|
13
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
Bundler.require(:default)
|
5
|
+
|
6
|
+
require 'supermodel' # shouldn't Bundler do this already?
|
7
|
+
require 'active_support/all'
|
8
|
+
require 'matchers'
|
9
|
+
require 'cancan/matchers'
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.filter_run :focus => true
|
14
|
+
config.run_all_when_everything_filtered = true
|
15
|
+
config.mock_with :rspec
|
16
|
+
|
17
|
+
config.expect_with :rspec do |c|
|
18
|
+
c.syntax = :expect
|
19
|
+
end
|
20
|
+
|
21
|
+
config.before(:each) do
|
22
|
+
Project.delete_all
|
23
|
+
Category.delete_all
|
24
|
+
end
|
25
|
+
config.extend WithModel if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Working around CVE-2012-5664 requires us to convert all ID params
|
29
|
+
# to strings. Let's switch to using string IDs in tests, otherwise
|
30
|
+
# SuperModel and/or RR will fail (as strings are not fixnums).
|
31
|
+
|
32
|
+
module SuperModel
|
33
|
+
class Base
|
34
|
+
def generate_id
|
35
|
+
object_id.to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Ability
|
41
|
+
include CanCan::Ability
|
42
|
+
|
43
|
+
def initialize(user)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Category < SuperModel::Base
|
48
|
+
has_many :projects
|
49
|
+
end
|
50
|
+
|
51
|
+
module Sub
|
52
|
+
class Project < SuperModel::Base
|
53
|
+
belongs_to :category
|
54
|
+
attr_accessor :category # why doesn't SuperModel do this automatically?
|
55
|
+
|
56
|
+
def self.respond_to?(method, include_private = false)
|
57
|
+
if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
|
58
|
+
true
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Project < SuperModel::Base
|
67
|
+
belongs_to :category
|
68
|
+
attr_accessor :category # why doesn't SuperModel do this automatically?
|
69
|
+
|
70
|
+
def self.respond_to?(method, include_private = false)
|
71
|
+
if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
|
72
|
+
true
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|