mongoid_ability 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +7 -0
  4. data/README.md +55 -23
  5. data/lib/cancancan/model_adapters/mongoid_adapter.rb +156 -0
  6. data/lib/cancancan/model_additions.rb +30 -0
  7. data/lib/mongoid_ability.rb +12 -12
  8. data/lib/mongoid_ability/ability.rb +67 -26
  9. data/lib/mongoid_ability/find_lock.rb +71 -0
  10. data/lib/mongoid_ability/lock.rb +25 -16
  11. data/lib/mongoid_ability/locks_decorator.rb +45 -0
  12. data/lib/mongoid_ability/owner.rb +23 -3
  13. data/lib/mongoid_ability/subject.rb +10 -22
  14. data/lib/mongoid_ability/version.rb +1 -1
  15. data/test/cancancan/model_adapters/mongoid_adapter_options_test.rb +102 -0
  16. data/test/cancancan/model_adapters/mongoid_adapter_test.rb +207 -0
  17. data/test/mongoid_ability/ability_basic_benchmark.rb +30 -0
  18. data/test/mongoid_ability/ability_basic_test.rb +44 -13
  19. data/test/mongoid_ability/ability_marshal_test.rb +17 -0
  20. data/test/mongoid_ability/ability_options_test.rb +93 -0
  21. data/test/mongoid_ability/ability_test.rb +87 -106
  22. data/test/mongoid_ability/find_lock_test.rb +67 -0
  23. data/test/mongoid_ability/lock_test.rb +32 -40
  24. data/test/mongoid_ability/owner_locks_test.rb +14 -21
  25. data/test/mongoid_ability/owner_test.rb +4 -14
  26. data/test/mongoid_ability/subject_test.rb +32 -58
  27. data/test/support/test_classes/my_lock.rb +8 -13
  28. data/test/support/test_classes/my_owner.rb +13 -15
  29. data/test/support/test_classes/my_role.rb +9 -11
  30. data/test/support/test_classes/my_subject.rb +16 -9
  31. data/test/test_helper.rb +12 -2
  32. metadata +18 -25
  33. data/lib/mongoid_ability/accessible_query_builder.rb +0 -64
  34. data/lib/mongoid_ability/resolve_default_locks.rb +0 -17
  35. data/lib/mongoid_ability/resolve_inherited_locks.rb +0 -35
  36. data/lib/mongoid_ability/resolve_locks.rb +0 -12
  37. data/lib/mongoid_ability/resolve_owner_locks.rb +0 -35
  38. data/lib/mongoid_ability/resolver.rb +0 -24
  39. data/lib/mongoid_ability/values_for_accessible_query.rb +0 -74
  40. data/test/mongoid_ability/ability_syntactic_sugar_test.rb +0 -32
  41. data/test/mongoid_ability/accessible_query_builder_test.rb +0 -119
  42. data/test/mongoid_ability/can_options_test.rb +0 -17
  43. data/test/mongoid_ability/resolve_default_locks_test.rb +0 -41
  44. data/test/mongoid_ability/resolve_inherited_locks_test.rb +0 -50
  45. data/test/mongoid_ability/resolve_owner_locks_test.rb +0 -56
  46. data/test/mongoid_ability/resolver_test.rb +0 -23
  47. data/test/mongoid_ability/subject_accessible_by_test.rb +0 -147
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ module MongoidAbility
4
+ describe FindLock do
5
+ let(:owner) { MyOwner.new }
6
+
7
+ describe 'default lock' do
8
+ before { MySubject.default_lock MyLock, :read, true }
9
+
10
+ it { FindLock.call(owner, :read, MySubject).must_equal MySubject.default_locks.for_action(:read).first }
11
+ it { FindLock.call(owner, :read, MySubject1).must_equal MySubject.default_locks.for_action(:read).first }
12
+ end
13
+
14
+ describe 'inherited lock' do
15
+ before { MySubject.default_lock MyLock, :read, true }
16
+
17
+ let(:lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
18
+ let(:role) { MyRole.new(my_locks: [lock]) }
19
+ let(:owner) { MyOwner.new(my_roles: [role]) }
20
+
21
+ it { FindLock.call(owner, :read, MySubject).must_equal lock }
22
+
23
+ describe 'conflicting locks' do
24
+ let(:lock_1) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
25
+ let(:lock_2) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
26
+
27
+ let(:role_1) { MyRole.new(my_locks: [lock_1]) }
28
+ let(:role_2) { MyRole.new(my_locks: [lock_2]) }
29
+ let(:owner) { MyOwner.new(my_roles: [role_1, role_2]) }
30
+
31
+ it { FindLock.call(owner, :read, MySubject).must_equal lock_1 }
32
+ end
33
+
34
+ describe 'id lock' do
35
+ let(:my_subject) { MySubject.new }
36
+ let(:other_subject) { MySubject.new }
37
+ let(:lock_1) { MyLock.new(subject_type: my_subject.model_name, subject_id: my_subject.id, action: :read, outcome: false) }
38
+ let(:lock_2) { MyLock.new(subject_type: other_subject.model_name, subject_id: other_subject.id, action: :read, outcome: false) }
39
+ let(:role) { MyRole.new(my_locks: [lock_1, lock_2]) }
40
+ let(:owner) { MyOwner.new(my_roles: [role]) }
41
+
42
+ it { FindLock.call(owner, :read, MySubject).must_equal MySubject.default_locks.for_action(:read).first }
43
+ it { FindLock.call(owner, :read, my_subject.class, my_subject.id).must_equal lock_1 }
44
+ end
45
+ end
46
+
47
+ describe 'owned lock' do
48
+ before { MySubject.default_lock MyLock, :read, true }
49
+
50
+ let(:lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
51
+ let(:owner) { MyOwner.new(my_locks: [lock]) }
52
+
53
+ it { FindLock.call(owner, :read, MySubject).must_equal lock }
54
+
55
+ describe 'id lock' do
56
+ let(:my_subject) { MySubject.new }
57
+ let(:other_subject) { MySubject.new }
58
+ let(:lock_1) { MyLock.new(subject_type: my_subject.model_name, subject_id: my_subject.id, action: :read, outcome: false) }
59
+ let(:lock_2) { MyLock.new(subject_type: other_subject.model_name, subject_id: other_subject.id, action: :read, outcome: false) }
60
+ let(:owner) { MyOwner.new(my_locks: [lock_1, lock_2]) }
61
+
62
+ it { FindLock.call(owner, :read, MySubject).must_equal MySubject.default_locks.for_action(:read).first }
63
+ it { FindLock.call(owner, :read, my_subject.class, my_subject.id).must_equal lock_1 }
64
+ end
65
+ end
66
+ end
67
+ end
@@ -3,13 +3,10 @@ require 'test_helper'
3
3
  module MongoidAbility
4
4
  describe Lock do
5
5
  subject { MyLock.new }
6
+
6
7
  let(:my_subject) { MySubject.new }
7
8
  let(:inherited_lock) { MyLock1.new }
8
9
 
9
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: true)] }
10
- let(:my_subject_1_default_locks) { [MyLock.new(subject_type: MySubject1, action: :false, outcome: true)] }
11
- let(:my_subject_2_default_locks) { [] }
12
-
13
10
  # ---------------------------------------------------------------------
14
11
 
15
12
  it { subject.must_respond_to :action }
@@ -55,47 +52,42 @@ module MongoidAbility
55
52
 
56
53
  # ---------------------------------------------------------------------
57
54
 
55
+ describe 'sort' do
56
+ let(:lock0) { MyLock.new(subject_type: MySubject, action: :update, outcome: false) }
57
+ let(:lock1) { MyLock.new(subject_type: MySubject, action: :update, outcome: true) }
58
+ let(:lock2) { MyLock.new(subject_type: MySubject, action: :read, outcome: false, options: { override: true }) }
59
+ let(:lock3) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
60
+ let(:lock4) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
61
+
62
+ let(:owner) { MyOwner.new(my_locks: [lock1, lock2, lock3, lock4]) }
63
+
64
+ let(:sorted_locks) { owner.my_locks.sort(&Lock.sort) }
65
+
66
+ it { sorted_locks[0].must_equal lock4 }
67
+ it { sorted_locks[3].must_equal lock1 }
68
+ end
69
+
70
+ # ---------------------------------------------------------------------
71
+
58
72
  describe '#inherited_outcome' do
59
- let(:my_subject) { MySubject.new }
60
- let(:subject_type_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
61
- let(:subject_lock) { MyLock.new(subject: my_subject, action: :read, outcome: true) }
62
- let(:owner) { MyOwner.new(my_locks: [subject_type_lock, subject_lock]) }
73
+ before(:all) { MySubject.default_lock MyLock, :read, true }
63
74
 
64
- before do
65
- @ability = Ability.new(owner) # initialize owner
66
- end
75
+ let(:owner) { MyOwner.new(my_locks: [
76
+ MyLock.new(subject_type: MySubject, action: :read, outcome: false),
77
+ MyLock.new(subject: my_subject, action: :read, outcome: true)
78
+ ]) }
67
79
 
68
- it 'does not affect calculated_outcome' do
69
- MySubject.stub :default_locks, my_subject_default_locks do
70
- MySubject1.stub :default_locks, my_subject_1_default_locks do
71
- MySubject2.stub :default_locks, my_subject_2_default_locks do
72
- @ability.can?(:read, my_subject).must_equal true
73
- end
74
- end
75
- end
76
- end
80
+ let(:ability) { Ability.new(owner) }
77
81
 
78
- it 'returns calculated_outcome without this lock' do
79
- MySubject.stub :default_locks, my_subject_default_locks do
80
- MySubject1.stub :default_locks, my_subject_1_default_locks do
81
- MySubject2.stub :default_locks, my_subject_2_default_locks do
82
- subject_lock.inherited_outcome.must_equal false
83
- subject_type_lock.inherited_outcome.must_equal true
84
- end
85
- end
86
- end
87
- end
82
+ let(:subject_type_lock) { owner.my_locks.detect(&:class_lock?) }
83
+ let(:subject_lock) { owner.my_locks.detect(&:id_lock?) }
84
+ let(:default_lock) { MySubject.default_locks.detect { |l| l.action == :read } }
88
85
 
89
- it 'returns calculated_outcome for default locks' do
90
- MySubject.stub :default_locks, my_subject_default_locks do
91
- MySubject1.stub :default_locks, my_subject_1_default_locks do
92
- MySubject2.stub :default_locks, my_subject_2_default_locks do
93
- lock = MySubject.default_locks.detect { |l| l.action == :read }
94
- lock.inherited_outcome.must_equal true
95
- end
96
- end
97
- end
98
- end
86
+ it { ability.can?(:read, my_subject).must_equal true }
87
+
88
+ it { subject_lock.inherited_outcome.must_equal false }
89
+ it { subject_type_lock.inherited_outcome.must_equal true }
90
+ it { default_lock.inherited_outcome.must_equal true }
99
91
  end
100
92
  end
101
93
  end
@@ -4,34 +4,27 @@ module MongoidAbility
4
4
  describe 'owner locks test' do
5
5
  subject { MySubject.new }
6
6
 
7
- let(:subject_lock) { MyLock.new(action: :read, subject: subject, outcome: false) }
8
- let(:subject_type_lock) { MyLock.new(action: :read, subject_type: subject.class, outcome: false) }
9
-
10
7
  let(:owner) { MyOwner.new }
11
8
  let(:ability) { Ability.new(owner) }
12
9
 
13
- let(:default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: true)] }
14
-
15
10
  describe 'when lock for subject' do
16
- before { owner.my_locks = [subject_lock] }
17
-
18
- it 'applies it' do
19
- MySubject.stub :default_locks, default_locks do
20
- ability.can?(:read, subject.class).must_equal true
21
- ability.can?(:read, subject).must_equal false
22
- end
23
- end
11
+ let(:subject_lock) { MyLock.new(action: :read, subject: subject, outcome: false) }
12
+ let(:owner) { MyOwner.new(my_locks: [subject_lock]) }
13
+
14
+ before(:all) { MySubject.default_lock MyLock, :read, true }
15
+
16
+ it { ability.can?(:read, subject.class).must_equal true }
17
+ it { ability.can?(:read, subject).must_equal false }
24
18
  end
25
19
 
26
20
  describe 'when lock for subject type' do
27
- before { owner.my_locks = [subject_type_lock] }
28
-
29
- it 'applies it' do
30
- MySubject.stub :default_locks, default_locks do
31
- ability.can?(:read, subject.class).must_equal false
32
- ability.can?(:read, subject).must_equal false
33
- end
34
- end
21
+ let(:subject_type_lock) { MyLock.new(action: :read, subject_type: subject.class, outcome: false) }
22
+ let(:owner) { MyOwner.new(my_locks: [subject_type_lock]) }
23
+
24
+ before(:all) { MySubject.default_lock MyLock, :read, true }
25
+
26
+ it { ability.can?(:read, subject.class).must_equal false }
27
+ it { ability.can?(:read, subject).must_equal false }
35
28
  end
36
29
  end
37
30
  end
@@ -13,9 +13,7 @@ module MongoidAbility
13
13
  subject.run_callbacks(:save)
14
14
  end
15
15
 
16
- it 'prefers closed locks' do
17
- subject.my_locks.sort.must_equal [closed_lock].sort
18
- end
16
+ it { subject.my_locks.sort(&Lock.sort).must_equal [closed_lock].sort(&Lock.sort) }
19
17
 
20
18
  describe 'locks relation' do
21
19
  it { subject.class.locks_relation_name.must_equal :my_locks }
@@ -29,17 +27,9 @@ module MongoidAbility
29
27
  let(:other_lock) { MyLock.new(action: :update, subject: MySubject.new) }
30
28
  let(:owner) { MyOwner.new(my_locks: [subject_type_lock, subject_lock]) }
31
29
 
32
- it 'returns true when lock for same action & subject_type' do
33
- owner.has_lock?(subject_type_lock).must_equal true
34
- end
35
-
36
- it 'returns true when lock for same action & subject' do
37
- owner.has_lock?(subject_lock).must_equal true
38
- end
39
-
40
- it 'returns false for non existing lock' do
41
- owner.has_lock?(other_lock).must_equal false
42
- end
30
+ it { owner.has_lock?(subject_type_lock).must_equal true }
31
+ it { owner.has_lock?(subject_lock).must_equal true }
32
+ it { owner.has_lock?(other_lock).must_equal false }
43
33
  end
44
34
  end
45
35
  end
@@ -2,79 +2,53 @@ require 'test_helper'
2
2
 
3
3
  module MongoidAbility
4
4
  describe Subject do
5
- let(:my_subject_default_locks) { [] }
6
- let(:my_subject_1_default_locks) { [] }
7
- let(:my_subject_2_default_locks) { [] }
8
-
9
5
  describe '.default_lock' do
10
- it 'stores them' do
11
- MySubject.stub :default_locks, my_subject_default_locks do
12
- MySubject1.stub :default_locks, my_subject_1_default_locks do
13
- MySubject2.stub :default_locks, my_subject_2_default_locks do
14
- MySubject.default_lock MyLock, :read, true
15
- MySubject.default_lock MyLock, :update, true
16
- MySubject1.default_lock MyLock1, :update, false
17
-
18
- MySubject.default_locks.map(&:action).map(&:to_s).sort.must_equal %w(read update)
19
- MySubject1.default_locks.map(&:action).map(&:to_s).sort.must_equal %w(update)
20
- end
21
- end
22
- end
6
+ before(:all) do
7
+ MySubject.default_lock MyLock, :read, true
8
+ MySubject.default_lock MyLock, :update, true
9
+ MySubject1.default_lock MyLock1, :update, false
23
10
  end
11
+
12
+ it { MySubject.default_locks.map(&:action).map(&:to_s).sort.must_equal %w(read update) }
13
+ it { MySubject1.default_locks.map(&:action).map(&:to_s).sort.must_equal %w(update) }
24
14
  end
25
15
 
26
16
  describe 'prevents conflicts' do
27
- it 'does not allow multiple locks for same action' do
28
- MySubject.stub :default_locks, my_subject_default_locks do
29
- MySubject1.stub :default_locks, my_subject_1_default_locks do
30
- MySubject2.stub :default_locks, my_subject_2_default_locks do
31
- MySubject.default_lock MyLock1, :read, false
32
- MySubject1.default_lock MyLock, :read, true
33
-
34
- MySubject.default_locks.count { |l| l.action == :read }.must_equal 1
35
- end
36
- end
17
+ describe 'multiple locks for same action' do
18
+ before(:all) do
19
+ MySubject.default_lock MyLock1, :read, false
20
+ MySubject1.default_lock MyLock, :read, true
37
21
  end
38
- end
39
22
 
40
- it 'replace existing locks with new attributes' do
41
- MySubject.stub :default_locks, my_subject_default_locks do
42
- MySubject1.stub :default_locks, my_subject_1_default_locks do
43
- MySubject2.stub :default_locks, my_subject_2_default_locks do
44
- MySubject.default_lock MyLock1, :read, false
45
- MySubject1.default_lock MyLock, :read, true
23
+ it { MySubject.default_locks.count { |l| l.action == :read }.must_equal 1 }
24
+ end
46
25
 
47
- MySubject.default_locks.detect { |l| l.action == :read }.outcome.must_equal false
48
- end
49
- end
26
+ describe 'replace existing locks with new attributes' do
27
+ before(:all) do
28
+ MySubject.default_lock MyLock1, :read, false
29
+ MySubject1.default_lock MyLock, :read, true
50
30
  end
51
- end
52
31
 
53
- it 'replaces existing locks with new one' do
54
- MySubject.stub :default_locks, my_subject_default_locks do
55
- MySubject1.stub :default_locks, my_subject_1_default_locks do
56
- MySubject2.stub :default_locks, my_subject_2_default_locks do
57
- MySubject.default_lock MyLock1, :read, false
58
- MySubject1.default_lock MyLock, :read, true
32
+ it { MySubject.default_locks.detect { |l| l.action == :read }.outcome.must_equal false }
33
+ end
59
34
 
60
- MySubject.default_locks.detect { |l| l.action == :read }.class.must_equal MyLock1
61
- end
62
- end
35
+ describe 'replaces existing locks with new one' do
36
+ before(:all) do
37
+ MySubject.default_lock MyLock1, :read, false
38
+ MySubject1.default_lock MyLock, :read, true
63
39
  end
64
- end
65
40
 
66
- it 'replaces superclass locks' do
67
- MySubject.stub :default_locks, my_subject_default_locks do
68
- MySubject1.stub :default_locks, my_subject_1_default_locks do
69
- MySubject2.stub :default_locks, my_subject_2_default_locks do
70
- MySubject.default_lock MyLock1, :read, false
71
- MySubject1.default_lock MyLock, :read, true
41
+ it { MySubject.default_locks.detect { |l| l.action == :read }.class.must_equal MyLock1 }
42
+ end
72
43
 
73
- MySubject1.default_locks.count.must_equal 1
74
- MySubject1.default_locks.detect { |l| l.action == :read }.outcome.must_equal true
75
- end
76
- end
44
+ describe 'replaces superclass locks' do
45
+ before(:all) do
46
+ MySubject.default_lock MyLock1, :read, false
47
+ MySubject1.default_lock MyLock, :read, true
77
48
  end
49
+
50
+ it { MySubject1.default_locks.count.must_equal 1 }
51
+ it { MySubject1.default_locks.detect { |l| l.action == :read }.outcome.must_equal true }
78
52
  end
79
53
  end
80
54
 
@@ -1,15 +1,10 @@
1
- module MongoidAbility
2
- class MyLock
3
- include Mongoid::Document
4
- include Mongoid::Timestamps
5
- include MongoidAbility::Lock
6
-
7
- embedded_in :owner, polymorphic: true, touch: true
8
- end
1
+ class MyLock
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ include MongoidAbility::Lock
9
5
 
10
- class MyLock1 < MyLock
11
- def calculated_outcome(opts = {})
12
- opts.fetch(:override, outcome)
13
- end
14
- end
6
+ embedded_in :owner, polymorphic: true, touch: true
7
+ end
8
+
9
+ class MyLock1 < MyLock
15
10
  end
@@ -1,21 +1,19 @@
1
- module MongoidAbility
2
- class MyOwner
3
- include Mongoid::Document
4
- include Mongoid::Timestamps
5
- include MongoidAbility::Owner
1
+ class MyOwner
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ include MongoidAbility::Owner
6
5
 
7
- embeds_many :my_locks, class_name: 'MongoidAbility::MyLock', as: :owner
8
- has_and_belongs_to_many :my_roles
6
+ embeds_many :my_locks, class_name: 'MyLock', as: :owner
7
+ has_and_belongs_to_many :my_roles
9
8
 
10
- def self.locks_relation_name
11
- :my_locks
12
- end
13
-
14
- def self.inherit_from_relation_name
15
- :my_roles
16
- end
9
+ def self.locks_relation_name
10
+ :my_locks
17
11
  end
18
12
 
19
- class MyOwner1 < MyOwner
13
+ def self.inherit_from_relation_name
14
+ :my_roles
20
15
  end
21
16
  end
17
+
18
+ class MyOwner1 < MyOwner
19
+ end
@@ -1,16 +1,14 @@
1
- module MongoidAbility
2
- class MyRole
3
- include Mongoid::Document
4
- include MongoidAbility::Owner
1
+ class MyRole
2
+ include Mongoid::Document
3
+ include MongoidAbility::Owner
5
4
 
6
- embeds_many :my_locks, class_name: 'MongoidAbility::MyLock', as: :owner
7
- has_and_belongs_to_many :my_owners
5
+ embeds_many :my_locks, class_name: 'MyLock', as: :owner
6
+ has_and_belongs_to_many :my_owners
8
7
 
9
- def self.locks_relation_name
10
- :my_locks
11
- end
8
+ def self.locks_relation_name
9
+ :my_locks
12
10
  end
11
+ end
13
12
 
14
- class MyRole1 < MyRole
15
- end
13
+ class MyRole1 < MyRole
16
14
  end
@@ -1,12 +1,19 @@
1
- module MongoidAbility
2
- class MySubject
3
- include Mongoid::Document
4
- include MongoidAbility::Subject
5
- end
1
+ class MySubject
2
+ include Mongoid::Document
3
+ include MongoidAbility::Subject
6
4
 
7
- class MySubject1 < MySubject
8
- end
5
+ field :str_val, type: String
6
+ field :override, type: Boolean, default: false
7
+ end
8
+
9
+ class MySubject1 < MySubject
10
+ end
11
+
12
+ class MySubject11 < MySubject
13
+ end
14
+
15
+ class MySubject2 < MySubject1
16
+ end
9
17
 
10
- class MySubject2 < MySubject1
11
- end
18
+ class MySubject21 < MySubject11
12
19
  end