mongoid_ability 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mongoid_ability/lock.rb +11 -2
- data/lib/mongoid_ability/subject.rb +42 -28
- data/lib/mongoid_ability/version.rb +1 -1
- data/test/mongoid_ability/lock_test.rb +37 -0
- data/test/mongoid_ability/subject_test.rb +93 -80
- data/test/test_helper.rb +22 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75dab60ffb6d4f20fcf4f7eedbf2c9e1768fde5b
|
4
|
+
data.tar.gz: 60f054142c90df34356e269c0cd5209181077da7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2c5bd37edba18e8ed18a133267810c0f99674c28de0269d5cec2bfc3c2637d2317d84031cf02f3ee3dcf2572f25c61715820420f839ae1b22f5d1fe783cba26
|
7
|
+
data.tar.gz: bc0373e909e72bee1afb5dbbfd0b3715c1e7581baf8e50527fbf859268d20165b3eb2d20b46fcb4cdab9c80642c65c7a42de6e52b565e3c0363a11cc348e184b
|
data/lib/mongoid_ability/lock.rb
CHANGED
@@ -24,8 +24,8 @@ module MongoidAbility
|
|
24
24
|
scope :for_subject_id, -> subject_id { where(subject_id: subject_id) }
|
25
25
|
scope :for_subject, -> subject { where(subject_type: subject.class.model_name, subject_id: subject.id) }
|
26
26
|
|
27
|
-
scope :class_locks, -> {
|
28
|
-
scope :id_locks, -> { ne(
|
27
|
+
scope :class_locks, -> { where(subject_id: nil) }
|
28
|
+
scope :id_locks, -> { ne(subject_id: nil) }
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -60,5 +60,14 @@ module MongoidAbility
|
|
60
60
|
self.subject_id.present?
|
61
61
|
end
|
62
62
|
|
63
|
+
# ---------------------------------------------------------------------
|
64
|
+
|
65
|
+
def conditions
|
66
|
+
res = { _type: subject_type }
|
67
|
+
res = res.merge(_id: subject_id) if subject_id.present?
|
68
|
+
res = { '$not' => res } if calculated_outcome == false
|
69
|
+
res
|
70
|
+
end
|
71
|
+
|
63
72
|
end
|
64
73
|
end
|
@@ -23,7 +23,7 @@ module MongoidAbility
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# ---------------------------------------------------------------------
|
26
|
-
|
26
|
+
|
27
27
|
# override if needed
|
28
28
|
# return for example 'MyLock'
|
29
29
|
def lock_class_name
|
@@ -31,7 +31,7 @@ module MongoidAbility
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# ---------------------------------------------------------------------
|
34
|
-
|
34
|
+
|
35
35
|
def self_and_ancestors_with_default_locks
|
36
36
|
self.ancestors.select{ |a| a.is_a?(Class) && a.respond_to?(:default_locks) }
|
37
37
|
end
|
@@ -41,40 +41,54 @@ module MongoidAbility
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# ---------------------------------------------------------------------
|
44
|
-
|
44
|
+
|
45
|
+
# TODO: obviously this could be cleaner
|
45
46
|
def accessible_by ability, action=:read
|
46
47
|
cr = self.criteria
|
47
48
|
|
48
49
|
return cr unless ability.user.present?
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
51
|
+
supercls = self.ancestors_with_default_locks.last || self
|
52
|
+
subject_classes = [supercls].concat(supercls.subclasses)
|
53
|
+
|
54
|
+
subject_classes.each do |cls|
|
55
|
+
|
56
|
+
roles_id_locks = ability.user.roles_relation.collect{ |role| role.locks_relation.for_subject_type(cls.to_s).id_locks.for_action(action) }.flatten
|
57
|
+
user_id_locks = ability.user.locks_relation.for_subject_type(cls.to_s).id_locks.for_action(action)
|
58
|
+
|
59
|
+
closed_roles_id_locks = roles_id_locks.to_a.select(&:closed?)
|
60
|
+
open_roles_id_locks = roles_id_locks.to_a.select(&:open?)
|
61
|
+
|
62
|
+
closed_user_id_locks = user_id_locks.to_a.select(&:closed?)
|
63
|
+
open_user_id_locks = user_id_locks.to_a.select(&:open?)
|
64
|
+
|
65
|
+
if ability.can?(action, cls)
|
66
|
+
excluded_ids = []
|
67
|
+
|
68
|
+
id_locks = closed_roles_id_locks.
|
69
|
+
reject{ |cl| open_roles_id_locks.any?{ |ol| ol.subject_id == cl.subject_id } }.
|
70
|
+
reject{ |cl| open_user_id_locks.any?{ |ol| ol.subject_id == cl.subject_id } }
|
71
|
+
|
72
|
+
id_locks += closed_user_id_locks
|
73
|
+
|
74
|
+
excluded_ids << id_locks.map(&:subject_id)
|
75
|
+
|
76
|
+
cr = cr.or(_type: cls.to_s, :_id.nin => excluded_ids.flatten)
|
77
|
+
else
|
78
|
+
included_ids = []
|
79
|
+
|
80
|
+
id_locks = open_roles_id_locks
|
81
|
+
id_locks += open_user_id_locks
|
82
|
+
|
83
|
+
included_ids << id_locks.map(&:subject_id)
|
84
|
+
|
85
|
+
cr = cr.or(_type: cls.to_s, :_id.in => included_ids.flatten)
|
86
|
+
end
|
73
87
|
end
|
88
|
+
|
89
|
+
cr
|
74
90
|
end
|
75
91
|
end
|
76
92
|
|
77
|
-
# =====================================================================
|
78
|
-
|
79
93
|
end
|
80
94
|
end
|
@@ -3,6 +3,7 @@ require 'test_helper'
|
|
3
3
|
module MongoidAbility
|
4
4
|
describe Lock do
|
5
5
|
|
6
|
+
let(:subject_test) { SubjectTest.new }
|
6
7
|
subject { TestLock.new }
|
7
8
|
|
8
9
|
# =====================================================================
|
@@ -51,6 +52,42 @@ module MongoidAbility
|
|
51
52
|
it 'has #id_lock?' do
|
52
53
|
subject.must_respond_to :id_lock?
|
53
54
|
end
|
55
|
+
|
56
|
+
describe '#criteria' do
|
57
|
+
let(:open_subject_type_lock) { TestLock.new(subject_type: subject_test.class.to_s, action: :read, outcome: true) }
|
58
|
+
let(:closed_subject_type_lock) { TestLock.new(subject_type: subject_test.class.to_s, action: :read, outcome: false) }
|
59
|
+
|
60
|
+
let(:open_subject_lock) { TestLock.new(subject: subject_test, action: :read, outcome: true) }
|
61
|
+
let(:closed_subject_lock) { TestLock.new(subject: subject_test, action: :read, outcome: false) }
|
62
|
+
|
63
|
+
it 'returns conditions Hash' do
|
64
|
+
open_subject_type_lock.conditions.must_be_kind_of Hash
|
65
|
+
closed_subject_type_lock.conditions.must_be_kind_of Hash
|
66
|
+
|
67
|
+
open_subject_lock.conditions.must_be_kind_of Hash
|
68
|
+
closed_subject_lock.conditions.must_be_kind_of Hash
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'when open' do
|
72
|
+
it 'includes subject_type' do
|
73
|
+
open_subject_type_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type })
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'includes id' do
|
77
|
+
open_subject_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id })
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'when closed' do
|
82
|
+
it 'excludes subject_type' do
|
83
|
+
closed_subject_type_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type }})
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'includes id' do
|
87
|
+
closed_subject_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id }})
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
54
91
|
end
|
55
92
|
|
56
93
|
end
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
module MongoidAbility
|
4
4
|
describe Subject do
|
5
5
|
|
6
|
-
def
|
6
|
+
def subject_type_lock subject_cls, outcome
|
7
7
|
TestLock.new(subject_type: subject_cls.to_s, action: :read, outcome: outcome)
|
8
8
|
end
|
9
9
|
|
@@ -13,18 +13,19 @@ module MongoidAbility
|
|
13
13
|
|
14
14
|
# ---------------------------------------------------------------------
|
15
15
|
|
16
|
-
subject {
|
16
|
+
subject { SubjectTest.new }
|
17
17
|
|
18
|
-
let(:subject_test_1) {
|
19
|
-
let(:subject_test_2) {
|
18
|
+
let(:subject_test_1) { SubjectTestOne.create! }
|
19
|
+
let(:subject_test_2) { SubjectTestTwo.create! }
|
20
20
|
|
21
|
-
let(:
|
21
|
+
# let(:embedded_test_subject_1) { EmbeddedTestSubject.new }
|
22
|
+
# let(:embedded_test_subject_2) { EmbeddedTestSubjectTwo.new }
|
23
|
+
# let(:embedded_test_subject_owner) { EmbeddedTestSubjectOwner.new(embedded_test_subjects: [ embedded_test_subject_1, embedded_test_subject_2 ]) }
|
22
24
|
|
23
|
-
let(:
|
24
|
-
let(:
|
25
|
-
let(:embedded_test_subject_owner) { EmbeddedTestSubjectOwner.new(embedded_test_subjects: [ embedded_test_subject_1, embedded_test_subject_2 ]) }
|
25
|
+
let(:role_1) { TestRole.new }
|
26
|
+
let(:role_2) { TestRole.new }
|
26
27
|
|
27
|
-
let(:user) { TestUser.new }
|
28
|
+
let(:user) { TestUser.new(roles: [role_1, role_2]) }
|
28
29
|
let(:ability) { Ability.new(user) }
|
29
30
|
|
30
31
|
# =====================================================================
|
@@ -53,131 +54,143 @@ module MongoidAbility
|
|
53
54
|
|
54
55
|
describe '.ancestors_with_default_locks' do
|
55
56
|
it 'lists ancestors with default locks' do
|
56
|
-
|
57
|
+
subject_test_1.class.ancestors_with_default_locks.must_equal [subject.class]
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
61
|
describe '.self_and_ancestors_with_default_locks' do
|
61
62
|
it 'lists self and ancestors with default locks' do
|
62
|
-
|
63
|
+
subject_test_1.class.self_and_ancestors_with_default_locks.must_equal [subject_test_1.class, subject.class]
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
67
|
# =====================================================================
|
67
68
|
|
68
69
|
describe '.accessible_by' do
|
70
|
+
before do
|
71
|
+
subject_test_1
|
72
|
+
subject_test_2
|
73
|
+
end
|
69
74
|
|
70
75
|
it 'returns Mongoid::Criteria' do
|
71
76
|
subject.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
|
72
|
-
embedded_test_subject_1.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
|
77
|
+
# embedded_test_subject_1.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
|
73
78
|
end
|
74
79
|
|
75
|
-
describe 'embedded relations' do
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
+
# describe 'embedded relations' do
|
81
|
+
# it 'returns correct criteria type' do
|
82
|
+
# embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).embedded?.must_equal true
|
83
|
+
# end
|
84
|
+
# end
|
80
85
|
|
81
86
|
# ---------------------------------------------------------------------
|
82
87
|
|
83
88
|
describe 'default locks' do
|
84
89
|
describe 'referenced relations' do
|
85
90
|
it 'returns everything when open' do
|
86
|
-
|
87
|
-
subject_test_2
|
88
|
-
|
89
|
-
subject.class.stub(:default_locks, [ default_lock(subject_test_1.class, true) ]) do
|
91
|
+
subject.class.stub(:default_locks, [ subject_type_lock(subject.class, true) ]) do
|
90
92
|
subject.class.accessible_by(ability).must_include subject_test_1
|
91
93
|
subject.class.accessible_by(ability).must_include subject_test_2
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
95
97
|
it 'returns nothing when closed' do
|
96
|
-
subject.class.stub(:default_locks, [
|
98
|
+
subject.class.stub(:default_locks, [ subject_type_lock(subject.class, false) ]) do
|
97
99
|
subject.class.accessible_by(ability).must_be :empty?
|
98
100
|
end
|
99
101
|
end
|
100
102
|
end
|
101
|
-
|
102
|
-
describe 'embedded relations' do
|
103
|
-
it 'returns everything when open' do
|
104
|
-
subject.class.stub(:default_locks, [ default_lock(embedded_test_subject_1.class, true) ]) do
|
105
|
-
embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_1
|
106
|
-
embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_2
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'returns nothing when closed' do
|
111
|
-
subject.class.stub(:default_locks, [ default_lock(embedded_test_subject_1.class, false) ]) do
|
112
|
-
embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_be :empty?
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
103
|
end
|
117
104
|
|
118
105
|
# ---------------------------------------------------------------------
|
119
106
|
|
120
|
-
describe '
|
121
|
-
describe '
|
122
|
-
it '
|
123
|
-
|
107
|
+
describe 'subject_type lock' do
|
108
|
+
describe 'on roles' do
|
109
|
+
it 'overrides default lock' do
|
110
|
+
role_1.test_locks = [ subject_type_lock(subject.class, false) ]
|
111
|
+
subject.class.accessible_by(ability).must_be :empty?
|
112
|
+
end
|
113
|
+
it 'takes the most permissive of roles' do
|
114
|
+
role_1.test_locks = [ subject_type_lock(subject.class, false) ]
|
115
|
+
role_2.test_locks = [ subject_type_lock(subject.class, true) ]
|
124
116
|
subject.class.accessible_by(ability).must_include subject_test_1
|
125
|
-
subject.class.accessible_by(ability).
|
117
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
126
118
|
end
|
127
119
|
end
|
128
120
|
|
129
|
-
describe '
|
130
|
-
it '
|
131
|
-
user.test_locks = [
|
132
|
-
|
133
|
-
|
121
|
+
describe 'on user' do
|
122
|
+
it 'overrides default lock' do
|
123
|
+
user.test_locks = [ subject_type_lock(subject.class, false) ]
|
124
|
+
subject.class.accessible_by(ability).must_be :empty?
|
125
|
+
end
|
126
|
+
it 'overrides role locks' do
|
127
|
+
role_1.test_locks = [ subject_type_lock(subject.class, false) ]
|
128
|
+
user.test_locks = [ subject_type_lock(subject.class, true) ]
|
129
|
+
subject.class.accessible_by(ability).must_include subject_test_1
|
130
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
134
131
|
end
|
135
132
|
end
|
136
133
|
end
|
137
134
|
|
138
135
|
# ---------------------------------------------------------------------
|
139
136
|
|
140
|
-
describe '
|
141
|
-
describe '
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
137
|
+
describe 'subject_id lock' do
|
138
|
+
describe 'on roles' do
|
139
|
+
it 'overrides default lock' do
|
140
|
+
role_1.test_locks = [ subject_lock(subject_test_1, false) ]
|
141
|
+
subject.class.accessible_by(ability).wont_include subject_test_1
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'overrides default negative lock' do
|
145
|
+
subject.class.stub(:default_locks, [ subject_type_lock(subject_test_1.class, false) ]) do
|
146
|
+
role_1.test_locks = [ subject_lock(subject_test_1, true) ]
|
147
|
+
subject.class.accessible_by(ability).must_include subject_test_1
|
149
148
|
end
|
150
149
|
end
|
151
150
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
151
|
+
it 'overrides subject_type lock' do
|
152
|
+
role_1.test_locks = [ subject_type_lock(subject_test_2.class, false) ]
|
153
|
+
role_2.test_locks = [ subject_lock(subject_test_2, true) ]
|
154
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'overrides default negative lock' do
|
158
|
+
subject.class.stub(:default_locks, [ subject_type_lock(subject_test_2.class, false) ]) do
|
159
|
+
role_2.test_locks = [ subject_lock(subject_test_2, true) ]
|
160
|
+
subject.class.accessible_by(ability).wont_include subject_test_1
|
161
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
159
162
|
end
|
160
163
|
end
|
164
|
+
|
165
|
+
it 'takes the most permissive of roles' do
|
166
|
+
role_1.test_locks = [ subject_lock(subject_test_2, false) ]
|
167
|
+
role_2.test_locks = [ subject_lock(subject_test_2, true) ]
|
168
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
169
|
+
end
|
161
170
|
end
|
162
171
|
|
163
|
-
describe '
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
+
describe 'on user' do
|
173
|
+
it 'overrides default lock' do
|
174
|
+
user.test_locks = [ subject_lock(subject_test_1, false) ]
|
175
|
+
subject.class.accessible_by(ability).wont_include subject_test_1
|
176
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'overrides subject_type lock' do
|
180
|
+
user.test_locks = [ subject_type_lock(subject_test_1.class, true), subject_lock(subject_test_1, false) ]
|
181
|
+
subject.class.accessible_by(ability).wont_include subject_test_1
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'overrides role locks' do
|
185
|
+
role_1.test_locks = [ subject_lock(subject_test_2, false) ]
|
186
|
+
user.test_locks = [ subject_lock(subject_test_2, true) ]
|
187
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
172
188
|
end
|
173
189
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).wont_include embedded_test_subject_1
|
179
|
-
embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_2
|
180
|
-
end
|
190
|
+
it 'overrides default negative lock' do
|
191
|
+
subject.class.stub(:default_locks, [ subject_type_lock(subject_test_2.class, false) ]) do
|
192
|
+
user.test_locks = [ subject_lock(subject_test_2, true) ]
|
193
|
+
subject.class.accessible_by(ability).must_include subject_test_2
|
181
194
|
end
|
182
195
|
end
|
183
196
|
end
|
@@ -187,4 +200,4 @@ module MongoidAbility
|
|
187
200
|
end
|
188
201
|
end
|
189
202
|
|
190
|
-
end
|
203
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -71,26 +71,36 @@ end
|
|
71
71
|
|
72
72
|
# ---------------------------------------------------------------------
|
73
73
|
|
74
|
-
class
|
74
|
+
class SubjectTest
|
75
75
|
include Mongoid::Document
|
76
76
|
include MongoidAbility::Subject
|
77
|
-
end
|
78
77
|
|
79
|
-
class TestSubject < TestSubjectSuper
|
80
78
|
default_lock :read, true
|
81
79
|
end
|
82
80
|
|
83
|
-
class
|
84
|
-
include Mongoid::Document
|
85
|
-
include MongoidAbility::Subject
|
86
|
-
|
87
|
-
embeds_many :embedded_test_subjects
|
81
|
+
class SubjectTestOne < SubjectTest
|
88
82
|
end
|
89
83
|
|
90
|
-
class
|
91
|
-
embedded_in :embedded_test_subject_owner
|
84
|
+
class SubjectTestTwo < SubjectTest
|
92
85
|
end
|
93
86
|
|
87
|
+
|
88
|
+
|
89
|
+
# class EmbeddedTestSubjectOwner
|
90
|
+
# include Mongoid::Document
|
91
|
+
# include MongoidAbility::Subject
|
92
|
+
|
93
|
+
# embeds_many :embedded_test_subjects
|
94
|
+
# end
|
95
|
+
|
96
|
+
# class EmbeddedTestSubject < TestSubject
|
97
|
+
# embedded_in :embedded_test_subject_owner
|
98
|
+
# end
|
99
|
+
|
100
|
+
# class EmbeddedTestSubjectTwo < TestSubject
|
101
|
+
# embedded_in :embedded_test_subject_owner
|
102
|
+
# end
|
103
|
+
|
94
104
|
# ---------------------------------------------------------------------
|
95
105
|
|
96
106
|
class TestAbilityResolverSubject
|
@@ -114,6 +124,8 @@ end
|
|
114
124
|
class TestAbilitySubject < TestAbilitySubjectSuper1
|
115
125
|
end
|
116
126
|
|
127
|
+
# ---------------------------------------------------------------------
|
128
|
+
|
117
129
|
class TestRole
|
118
130
|
include Mongoid::Document
|
119
131
|
include MongoidAbility::Owner
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_ability
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomas Celizna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cancancan
|