mongoid_ability 1.0.0 → 2.0.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.
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