mongoid_ability 0.0.3 → 0.0.4
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 +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
|