mongoid-multitenancy-2 2.0.3
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 +7 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +54 -0
- data/Gemfile +15 -0
- data/LICENSE.TXT +20 -0
- data/README.md +283 -0
- data/Rakefile +8 -0
- data/gemfiles/Gemfile.mongoid-6 +14 -0
- data/gemfiles/Gemfile.mongoid-7 +14 -0
- data/lib/mongoid-multitenancy.rb +1 -0
- data/lib/mongoid/multitenancy.rb +34 -0
- data/lib/mongoid/multitenancy/document.rb +176 -0
- data/lib/mongoid/multitenancy/validators/tenancy.rb +36 -0
- data/lib/mongoid/multitenancy/validators/tenant_uniqueness.rb +67 -0
- data/lib/mongoid/multitenancy/version.rb +6 -0
- data/mongoid-multitenancy.gemspec +19 -0
- data/spec/immutable_spec.rb +46 -0
- data/spec/indexable_spec.rb +35 -0
- data/spec/inheritance_spec.rb +22 -0
- data/spec/mandatory_spec.rb +116 -0
- data/spec/models/account.rb +5 -0
- data/spec/models/immutable.rb +15 -0
- data/spec/models/indexable.rb +10 -0
- data/spec/models/mandatory.rb +15 -0
- data/spec/models/mutable.rb +15 -0
- data/spec/models/mutable_child.rb +9 -0
- data/spec/models/no_scopable.rb +11 -0
- data/spec/models/optional.rb +15 -0
- data/spec/models/optional_exclude.rb +15 -0
- data/spec/mongoid-multitenancy_spec.rb +37 -0
- data/spec/mutable_child_spec.rb +46 -0
- data/spec/mutable_spec.rb +50 -0
- data/spec/optional_exclude_spec.rb +71 -0
- data/spec/optional_spec.rb +207 -0
- data/spec/scopable_spec.rb +29 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/mongoid_matchers.rb +17 -0
- data/spec/support/shared_examples.rb +80 -0
- metadata +119 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Inheritance' do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
Mongoid::Multitenancy.current_tenant = client
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'class' do
|
13
|
+
it 'uses inheritance pattern' do
|
14
|
+
MutableChild.create!(title: 'title X', slug: 'page-x')
|
15
|
+
expect(Mutable.last).to be_a MutableChild
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'keeps options' do
|
19
|
+
expect(AnotherMutableChild.new(title: 'title X', slug: 'page-x')).to be_valid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mandatory do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:item) do
|
13
|
+
Mandatory.new(title: 'title X', slug: 'page-x')
|
14
|
+
end
|
15
|
+
|
16
|
+
it_behaves_like 'a tenantable model'
|
17
|
+
it { is_expected.to validate_tenant_uniqueness_of(:slug) }
|
18
|
+
|
19
|
+
describe '.shared' do
|
20
|
+
it 'is defined' do
|
21
|
+
expect(Mandatory).to respond_to(:shared)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '.unshared' do
|
26
|
+
it 'is defined' do
|
27
|
+
expect(Mandatory).to respond_to(:unshared)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.default_scope' do
|
32
|
+
before do
|
33
|
+
Mongoid::Multitenancy.with_tenant(client) { @itemX = Mandatory.create!(title: 'title X', slug: 'article-x') }
|
34
|
+
Mongoid::Multitenancy.with_tenant(another_client) { @itemY = Mandatory.create!(title: 'title Y', slug: 'article-y') }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with a current tenant' do
|
38
|
+
before do
|
39
|
+
Mongoid::Multitenancy.current_tenant = another_client
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'filters on the current tenant' do
|
43
|
+
expect(Mandatory.all.to_a).to match_array [@itemY]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'without a current tenant' do
|
48
|
+
before do
|
49
|
+
Mongoid::Multitenancy.current_tenant = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'does not filter on any tenant' do
|
53
|
+
expect(Mandatory.all.to_a).to match_array [@itemX, @itemY]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#delete_all' do
|
59
|
+
before do
|
60
|
+
Mongoid::Multitenancy.with_tenant(client) { @itemX = Mandatory.create!(title: 'title X', slug: 'article-x') }
|
61
|
+
Mongoid::Multitenancy.with_tenant(another_client) { @itemY = Mandatory.create!(title: 'title Y', slug: 'article-y') }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with a current tenant' do
|
65
|
+
it 'only deletes the current tenant' do
|
66
|
+
Mongoid::Multitenancy.with_tenant(another_client) { Mandatory.delete_all }
|
67
|
+
expect(Mandatory.all.to_a).to match_array [@itemX]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'without a current tenant' do
|
72
|
+
it 'deletes all the items' do
|
73
|
+
Mandatory.delete_all
|
74
|
+
expect(Mandatory.all.to_a).to be_empty
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#valid?' do
|
80
|
+
context 'with a tenant' do
|
81
|
+
before do
|
82
|
+
Mongoid::Multitenancy.current_tenant = client
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'is valid' do
|
86
|
+
expect(item).to be_valid
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with a uniqueness constraint' do
|
90
|
+
let(:duplicate) do
|
91
|
+
Mandatory.new(title: 'title Y', slug: 'page-x')
|
92
|
+
end
|
93
|
+
|
94
|
+
before do
|
95
|
+
item.save!
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'does not allow duplicates on the same tenant' do
|
99
|
+
expect(duplicate).not_to be_valid
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'allow duplicates on a different same tenant' do
|
103
|
+
Mongoid::Multitenancy.with_tenant(another_client) do
|
104
|
+
expect(duplicate).to be_valid
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'without a tenant' do
|
111
|
+
it 'is not valid' do
|
112
|
+
expect(item).not_to be_valid
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Immutable
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant(:tenant, class_name: 'Account', immutable: true)
|
6
|
+
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type: String
|
9
|
+
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
|
+
validates_presence_of :slug
|
12
|
+
validates_presence_of :title
|
13
|
+
|
14
|
+
index(title: 1)
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Mandatory
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant(:tenant, class_name: 'Account')
|
6
|
+
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type: String
|
9
|
+
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
|
+
validates_presence_of :slug
|
12
|
+
validates_presence_of :title
|
13
|
+
|
14
|
+
index(title: 1)
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Mutable
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant :tenant, class_name: 'Account', immutable: false, optional: false
|
6
|
+
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type: String
|
9
|
+
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
|
+
validates_presence_of :slug
|
12
|
+
validates_presence_of :title
|
13
|
+
|
14
|
+
index(title: 1)
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Optional
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant(:tenant, class_name: 'Account', optional: true)
|
6
|
+
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type: String
|
9
|
+
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
|
+
validates_presence_of :slug
|
12
|
+
validates_presence_of :title
|
13
|
+
|
14
|
+
index(title: 1)
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class OptionalExclude
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant(:tenant, class_name: 'Account', optional: true)
|
6
|
+
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type: String
|
9
|
+
|
10
|
+
validates_tenant_uniqueness_of :slug, exclude_shared: true
|
11
|
+
validates_presence_of :slug
|
12
|
+
validates_presence_of :title
|
13
|
+
|
14
|
+
index(title: 1)
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongoid::Multitenancy do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
Mongoid::Multitenancy.current_tenant = client
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.with_tenant' do
|
17
|
+
it 'changes temporary the current tenant within the block' do
|
18
|
+
Mongoid::Multitenancy.with_tenant(another_client) do
|
19
|
+
expect(Mongoid::Multitenancy.current_tenant).to eq another_client
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'restores the current tenant after the block' do
|
24
|
+
Mongoid::Multitenancy.with_tenant(another_client) { ; }
|
25
|
+
expect(Mongoid::Multitenancy.current_tenant).to eq client
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when the block fails' do
|
29
|
+
it 'restores the current tenant' do
|
30
|
+
begin
|
31
|
+
Mongoid::Multitenancy.with_tenant(another_client) { raise StandardError }
|
32
|
+
rescue StandardError; end
|
33
|
+
expect(Mongoid::Multitenancy.current_tenant).to eq client
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MutableChild do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:item) do
|
13
|
+
MutableChild.new(title: 'title X', slug: 'page-x')
|
14
|
+
end
|
15
|
+
|
16
|
+
it_behaves_like 'a tenantable model'
|
17
|
+
|
18
|
+
describe '#valid?' do
|
19
|
+
before do
|
20
|
+
Mongoid::Multitenancy.current_tenant = client
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when the tenant has not changed' do
|
24
|
+
before do
|
25
|
+
item.save!
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'is valid' do
|
29
|
+
item.title = 'title X (2)'
|
30
|
+
expect(item).to be_valid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the tenant has changed' do
|
35
|
+
before do
|
36
|
+
item.save!
|
37
|
+
Mongoid::Multitenancy.current_tenant = another_client
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'is valid' do
|
41
|
+
item.tenant = another_client
|
42
|
+
expect(item).to be_valid
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mutable do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:item) do
|
13
|
+
Mutable.new(title: 'title X', slug: 'page-x')
|
14
|
+
end
|
15
|
+
|
16
|
+
it_behaves_like 'a tenantable model'
|
17
|
+
|
18
|
+
describe '#valid?' do
|
19
|
+
before do
|
20
|
+
Mongoid::Multitenancy.current_tenant = client
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
Mongoid::Multitenancy.current_tenant = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the tenant has not changed' do
|
28
|
+
before do
|
29
|
+
item.save!
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'is valid' do
|
33
|
+
item.title = 'title X (2)'
|
34
|
+
expect(item).to be_valid
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when the tenant has changed' do
|
39
|
+
before do
|
40
|
+
item.save!
|
41
|
+
Mongoid::Multitenancy.current_tenant = another_client
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'is valid' do
|
45
|
+
item.tenant = another_client
|
46
|
+
expect(item).to be_valid
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OptionalExclude do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:item) do
|
13
|
+
OptionalExclude.new(title: 'title X', slug: 'page-x')
|
14
|
+
end
|
15
|
+
|
16
|
+
it_behaves_like 'a tenantable model'
|
17
|
+
|
18
|
+
describe '#valid?' do
|
19
|
+
context 'with a tenant' do
|
20
|
+
before do
|
21
|
+
Mongoid::Multitenancy.current_tenant = client
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is valid' do
|
25
|
+
expect(item).to be_valid
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with a uniqueness constraint' do
|
29
|
+
let(:duplicate) do
|
30
|
+
OptionalExclude.new(title: 'title Y', slug: 'page-x')
|
31
|
+
end
|
32
|
+
|
33
|
+
before do
|
34
|
+
item.save!
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not allow duplicates on the same tenant' do
|
38
|
+
expect(duplicate).not_to be_valid
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'allow duplicates on a different same tenant' do
|
42
|
+
Mongoid::Multitenancy.with_tenant(another_client) do
|
43
|
+
expect(duplicate).to be_valid
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'without a tenant' do
|
50
|
+
it 'is valid' do
|
51
|
+
expect(item).to be_valid
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with a uniqueness constraint' do
|
55
|
+
let(:duplicate) do
|
56
|
+
OptionalExclude.new(title: 'title Y', slug: 'page-x')
|
57
|
+
end
|
58
|
+
|
59
|
+
before do
|
60
|
+
item.save!
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'allow duplicates on any client' do
|
64
|
+
Mongoid::Multitenancy.with_tenant(client) do
|
65
|
+
expect(duplicate).to be_valid
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|