mongoid-multitenancy 0.4.4 → 1.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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.travis.yml +4 -3
- data/CHANGELOG.md +13 -0
- data/Gemfile +5 -5
- data/README.md +44 -15
- data/Rakefile +1 -1
- data/gemfiles/Gemfile.mongoid-4.0 +3 -4
- data/gemfiles/{Gemfile.mongoid-3.0 → Gemfile.mongoid-5.0} +3 -4
- data/lib/mongoid/multitenancy.rb +6 -10
- data/lib/mongoid/multitenancy/document.rb +117 -49
- data/lib/mongoid/multitenancy/validators/tenancy.rb +36 -0
- data/lib/mongoid/multitenancy/validators/tenant_uniqueness.rb +72 -0
- data/lib/mongoid/multitenancy/version.rb +2 -1
- data/mongoid-multitenancy.gemspec +8 -8
- data/spec/immutable_spec.rb +30 -18
- data/spec/indexable_spec.rb +6 -6
- data/spec/inheritance_spec.rb +11 -6
- data/spec/mandatory_spec.rb +70 -44
- data/spec/models/immutable.rb +3 -3
- data/spec/models/indexable.rb +2 -2
- data/spec/models/mandatory.rb +5 -5
- data/spec/models/mutable.rb +3 -3
- data/spec/models/optional.rb +5 -5
- data/spec/mongoid-multitenancy_spec.rb +17 -11
- data/spec/mutable_child_spec.rb +31 -17
- data/spec/mutable_spec.rb +34 -18
- data/spec/optional_spec.rb +88 -46
- data/spec/spec_helper.rb +16 -60
- data/spec/support/database_cleaner.rb +38 -0
- data/spec/support/mongoid_matchers.rb +17 -0
- data/spec/support/shared_examples.rb +81 -0
- metadata +14 -8
- data/lib/mongoid/validators/tenant_validator.rb +0 -20
- data/spec/support/mongoid.rb +0 -30
data/spec/models/indexable.rb
CHANGED
@@ -2,9 +2,9 @@ class Indexable
|
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Multitenancy::Document
|
4
4
|
|
5
|
-
field :title, :
|
5
|
+
field :title, type: String
|
6
6
|
|
7
7
|
tenant :client, class_name: 'Account', index: true, full_indexes: false
|
8
8
|
|
9
|
-
index({ :
|
9
|
+
index({ title: 1 })
|
10
10
|
end
|
data/spec/models/mandatory.rb
CHANGED
@@ -2,14 +2,14 @@ class Mandatory
|
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Multitenancy::Document
|
4
4
|
|
5
|
-
tenant(:client, :
|
5
|
+
tenant(:client, class_name: 'Account')
|
6
6
|
|
7
|
-
field :slug, :
|
8
|
-
field :title, :
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type:String
|
9
9
|
|
10
|
-
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
11
|
validates_presence_of :slug
|
12
12
|
validates_presence_of :title
|
13
13
|
|
14
|
-
index({ :
|
14
|
+
index({ title: 1 })
|
15
15
|
end
|
data/spec/models/mutable.rb
CHANGED
@@ -2,14 +2,14 @@ class Mutable
|
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Multitenancy::Document
|
4
4
|
|
5
|
-
tenant :client, :
|
5
|
+
tenant :client, class_name: 'Account', immutable: false, optional: false
|
6
6
|
|
7
7
|
field :slug, :type => String
|
8
8
|
field :title, :type => String
|
9
9
|
|
10
|
-
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
11
|
validates_presence_of :slug
|
12
12
|
validates_presence_of :title
|
13
13
|
|
14
|
-
index({ :
|
14
|
+
index({ title: 1 })
|
15
15
|
end
|
data/spec/models/optional.rb
CHANGED
@@ -2,14 +2,14 @@ class Optional
|
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Multitenancy::Document
|
4
4
|
|
5
|
-
tenant(:client, :
|
5
|
+
tenant(:client, class_name: 'Account', optional: true)
|
6
6
|
|
7
|
-
field :slug, :
|
8
|
-
field :title, :
|
7
|
+
field :slug, type: String
|
8
|
+
field :title, type: String
|
9
9
|
|
10
|
-
|
10
|
+
validates_tenant_uniqueness_of :slug
|
11
11
|
validates_presence_of :slug
|
12
12
|
validates_presence_of :title
|
13
13
|
|
14
|
-
index({ :
|
14
|
+
index({ title: 1 })
|
15
15
|
end
|
@@ -1,22 +1,28 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Mongoid::Multitenancy do
|
4
|
-
let(:client)
|
5
|
-
|
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
|
6
11
|
|
7
|
-
before
|
8
|
-
|
12
|
+
before do
|
13
|
+
Mongoid::Multitenancy.current_tenant = client
|
14
|
+
end
|
9
15
|
|
10
|
-
describe
|
11
|
-
it
|
16
|
+
describe '.with_tenant' do
|
17
|
+
it 'changes temporary the current tenant within the block' do
|
12
18
|
Mongoid::Multitenancy.with_tenant(another_client) do
|
13
|
-
Mongoid::Multitenancy.current_tenant.
|
19
|
+
expect(Mongoid::Multitenancy.current_tenant).to eq another_client
|
14
20
|
end
|
15
21
|
end
|
16
22
|
|
17
|
-
it
|
23
|
+
it 'restores the current tenant after the block' do
|
18
24
|
Mongoid::Multitenancy.with_tenant(another_client) do ; end
|
19
|
-
Mongoid::Multitenancy.current_tenant.
|
25
|
+
expect(Mongoid::Multitenancy.current_tenant).to eq client
|
20
26
|
end
|
21
27
|
end
|
22
|
-
end
|
28
|
+
end
|
data/spec/mutable_child_spec.rb
CHANGED
@@ -1,33 +1,47 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
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
|
4
11
|
|
5
|
-
let(:
|
6
|
-
|
12
|
+
let(:item) do
|
13
|
+
MutableChild.new(title: 'title X', slug: 'page-x')
|
14
|
+
end
|
7
15
|
|
8
|
-
|
9
|
-
before { Mongoid::Multitenancy.current_tenant = client; }
|
10
|
-
after { Mongoid::Multitenancy.current_tenant = nil }
|
16
|
+
it_behaves_like 'a tenantable model'
|
11
17
|
|
12
|
-
|
18
|
+
describe '#valid?' do
|
19
|
+
before do
|
20
|
+
Mongoid::Multitenancy.current_tenant = client
|
21
|
+
end
|
13
22
|
|
14
|
-
|
23
|
+
context 'when the tenant has not changed' do
|
24
|
+
before do
|
25
|
+
item.save!
|
26
|
+
end
|
15
27
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
item.title = "title X (2)"
|
20
|
-
item.should be_valid
|
28
|
+
it 'is valid' do
|
29
|
+
item.title = 'title X (2)'
|
30
|
+
expect(item).to be_valid
|
21
31
|
end
|
22
32
|
end
|
23
33
|
|
24
|
-
context
|
25
|
-
before
|
26
|
-
|
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
|
27
41
|
item.client = another_client
|
28
|
-
item.
|
42
|
+
expect(item).to be_valid
|
29
43
|
end
|
30
44
|
end
|
31
45
|
end
|
32
46
|
|
33
|
-
end
|
47
|
+
end
|
data/spec/mutable_spec.rb
CHANGED
@@ -1,34 +1,50 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Mutable do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
4
7
|
|
5
|
-
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
6
11
|
|
7
|
-
let(:
|
8
|
-
|
12
|
+
let(:item) do
|
13
|
+
Mutable.new(title: 'title X', slug: 'page-x')
|
14
|
+
end
|
9
15
|
|
10
|
-
|
11
|
-
before { Mongoid::Multitenancy.current_tenant = client; }
|
12
|
-
after { Mongoid::Multitenancy.current_tenant = nil }
|
16
|
+
it_behaves_like 'a tenantable model'
|
13
17
|
|
14
|
-
|
18
|
+
describe '#valid?' do
|
19
|
+
before do
|
20
|
+
Mongoid::Multitenancy.current_tenant = client
|
21
|
+
end
|
15
22
|
|
16
|
-
|
23
|
+
after do
|
24
|
+
Mongoid::Multitenancy.current_tenant = nil
|
25
|
+
end
|
17
26
|
|
18
|
-
context
|
19
|
-
before
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
23
35
|
end
|
24
36
|
end
|
25
37
|
|
26
|
-
context
|
27
|
-
before
|
28
|
-
|
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
|
29
45
|
item.client = another_client
|
30
|
-
item.
|
46
|
+
expect(item).to be_valid
|
31
47
|
end
|
32
48
|
end
|
33
49
|
end
|
34
|
-
end
|
50
|
+
end
|
data/spec/optional_spec.rb
CHANGED
@@ -2,83 +2,125 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Optional do
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
let(:client) do
|
6
|
+
Account.create!(name: 'client')
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:another_client) do
|
10
|
+
Account.create!(name: 'another client')
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:item) do
|
14
|
+
Optional.new(title: 'title X', slug: 'page-x')
|
15
|
+
end
|
7
16
|
|
8
|
-
|
9
|
-
|
17
|
+
it_behaves_like 'a tenantable model'
|
18
|
+
it { is_expected.to validate_tenant_uniqueness_of(:slug) }
|
10
19
|
|
11
|
-
describe
|
12
|
-
before
|
13
|
-
@itemC = Optional.create!(:
|
14
|
-
Mongoid::Multitenancy.with_tenant(client) { @itemX = Optional.create!(:
|
15
|
-
Mongoid::Multitenancy.with_tenant(another_client) { @itemY = Optional.create!(:
|
16
|
-
|
20
|
+
describe '.default_scope' do
|
21
|
+
before do
|
22
|
+
@itemC = Optional.create!(title: 'title C', slug: 'article-c')
|
23
|
+
Mongoid::Multitenancy.with_tenant(client) { @itemX = Optional.create!(title: 'title X', slug: 'article-x', :client => client) }
|
24
|
+
Mongoid::Multitenancy.with_tenant(another_client) { @itemY = Optional.create!(title: 'title Y', slug: 'article-y', :client => another_client) }
|
25
|
+
end
|
17
26
|
|
18
|
-
context
|
19
|
-
before
|
20
|
-
|
27
|
+
context 'with a current tenant' do
|
28
|
+
before do
|
29
|
+
Mongoid::Multitenancy.current_tenant = another_client
|
30
|
+
end
|
21
31
|
|
22
|
-
it
|
23
|
-
Optional.all.to_a.
|
32
|
+
it 'filters on the current tenant / free-tenant items' do
|
33
|
+
expect(Optional.all.to_a).to match_array [@itemY, @itemC]
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
27
|
-
context
|
28
|
-
before
|
37
|
+
context 'without a current tenant' do
|
38
|
+
before do
|
39
|
+
Mongoid::Multitenancy.current_tenant = nil
|
40
|
+
end
|
29
41
|
|
30
|
-
it
|
31
|
-
Optional.all.to_a.
|
42
|
+
it 'does not filter on any tenant' do
|
43
|
+
expect(Optional.all.to_a).to match_array [@itemC, @itemX, @itemY]
|
32
44
|
end
|
33
45
|
end
|
34
46
|
end
|
35
47
|
|
36
|
-
describe
|
37
|
-
before
|
38
|
-
@itemC = Optional.create!(:
|
39
|
-
Mongoid::Multitenancy.with_tenant(client) { @itemX = Optional.create!(:
|
40
|
-
Mongoid::Multitenancy.with_tenant(another_client) { @itemY = Optional.create!(:
|
41
|
-
|
48
|
+
describe '#delete_all' do
|
49
|
+
before do
|
50
|
+
@itemC = Optional.create!(title: 'title C', slug: 'article-c')
|
51
|
+
Mongoid::Multitenancy.with_tenant(client) { @itemX = Optional.create!(title: 'title X', slug: 'article-x', :client => client) }
|
52
|
+
Mongoid::Multitenancy.with_tenant(another_client) { @itemY = Optional.create!(title: 'title Y', slug: 'article-y', :client => another_client) }
|
53
|
+
end
|
42
54
|
|
43
|
-
context
|
44
|
-
it
|
55
|
+
context 'with a current tenant' do
|
56
|
+
it 'only deletes the current tenant / free-tenant items' do
|
45
57
|
Mongoid::Multitenancy.with_tenant(another_client) { Optional.delete_all }
|
46
|
-
Optional.all.to_a.
|
58
|
+
expect(Optional.all.to_a).to match_array [@itemX]
|
47
59
|
end
|
48
60
|
end
|
49
61
|
|
50
|
-
context
|
51
|
-
it
|
62
|
+
context 'without a current tenant' do
|
63
|
+
it 'deletes all the pages' do
|
52
64
|
Optional.delete_all
|
53
|
-
Optional.all.to_a.
|
65
|
+
expect(Optional.all.to_a).to be_empty
|
54
66
|
end
|
55
67
|
end
|
56
68
|
end
|
57
69
|
|
58
|
-
describe
|
59
|
-
|
70
|
+
describe '#valid?' do
|
71
|
+
context 'with a tenant' do
|
72
|
+
before do
|
73
|
+
item.client = client
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'is valid' do
|
77
|
+
expect(item).to be_valid
|
78
|
+
end
|
60
79
|
|
61
|
-
|
80
|
+
context 'with a uniqueness constraint' do
|
81
|
+
let(:duplicate) do
|
82
|
+
Optional.new(title: 'title Y', slug: 'page-x')
|
83
|
+
end
|
62
84
|
|
63
|
-
|
85
|
+
before do
|
86
|
+
item.save!
|
87
|
+
end
|
64
88
|
|
65
|
-
|
66
|
-
|
89
|
+
it 'does not allow duplicates on the same tenant' do
|
90
|
+
expect(duplicate).not_to be_valid
|
91
|
+
end
|
67
92
|
|
68
|
-
|
69
|
-
|
70
|
-
|
93
|
+
it 'allow duplicates on a different same tenant' do
|
94
|
+
Mongoid::Multitenancy.with_tenant(another_client) do
|
95
|
+
expect(duplicate).to be_valid
|
96
|
+
end
|
97
|
+
end
|
71
98
|
end
|
72
99
|
end
|
73
100
|
|
74
|
-
context
|
75
|
-
|
76
|
-
item.
|
77
|
-
item.client.should be_nil
|
101
|
+
context 'without a tenant' do
|
102
|
+
before do
|
103
|
+
item.client = nil
|
78
104
|
end
|
79
105
|
|
80
|
-
it
|
81
|
-
item.
|
106
|
+
it 'is valid' do
|
107
|
+
expect(item).to be_valid
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with a uniqueness constraint' do
|
111
|
+
let(:duplicate) do
|
112
|
+
Optional.new(title: 'title Y', slug: 'page-x')
|
113
|
+
end
|
114
|
+
|
115
|
+
before do
|
116
|
+
item.save!
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'does not allow duplicates on any client' do
|
120
|
+
Mongoid::Multitenancy.with_tenant(client) do
|
121
|
+
expect(duplicate).not_to be_valid
|
122
|
+
end
|
123
|
+
end
|
82
124
|
end
|
83
125
|
end
|
84
126
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
MODELS = File.join(File.dirname(__FILE__),
|
1
|
+
MODELS = File.join(File.dirname(__FILE__), 'models')
|
2
2
|
|
3
3
|
require 'simplecov'
|
4
4
|
require 'coveralls'
|
@@ -12,82 +12,38 @@ SimpleCov.start
|
|
12
12
|
require 'rspec'
|
13
13
|
require 'mongoid'
|
14
14
|
require 'mongoid-multitenancy'
|
15
|
-
require 'database_cleaner'
|
16
15
|
require 'mongoid-rspec'
|
17
16
|
|
18
|
-
|
17
|
+
if Mongoid::VERSION.start_with? '5'
|
18
|
+
Mongo::Logger.logger.level = ::Logger::FATAL
|
19
|
+
elsif Mongoid::VERSION.start_with? '4'
|
20
|
+
Moped.logger = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
require_relative 'support/shared_examples'
|
24
|
+
require_relative 'support/database_cleaner'
|
25
|
+
require_relative 'support/mongoid_matchers'
|
19
26
|
|
20
27
|
Dir["#{MODELS}/*.rb"].each { |f| require f }
|
21
28
|
|
22
29
|
Mongoid.configure do |config|
|
23
|
-
config.connect_to
|
30
|
+
config.connect_to 'mongoid_multitenancy'
|
24
31
|
end
|
25
32
|
|
26
|
-
Mongoid.logger =
|
27
|
-
|
28
|
-
DatabaseCleaner.orm = "mongoid"
|
33
|
+
Mongoid.logger = nil
|
29
34
|
|
30
35
|
RSpec.configure do |config|
|
31
36
|
config.include Mongoid::Matchers
|
32
37
|
|
33
|
-
config.
|
34
|
-
|
38
|
+
config.expect_with :rspec do |c|
|
39
|
+
c.syntax = :expect
|
35
40
|
end
|
36
41
|
|
37
42
|
config.before(:each) do
|
38
|
-
DatabaseCleaner.start
|
39
|
-
end
|
40
|
-
|
41
|
-
config.after(:each) do
|
42
43
|
DatabaseCleaner.clean
|
43
44
|
end
|
44
|
-
end
|
45
|
-
|
46
|
-
shared_examples_for "a tenantable model" do
|
47
|
-
|
48
|
-
it { should belong_to(:client) }
|
49
|
-
it { should have_index_for(:client_id => 1, :title => 1) }
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
shared_examples_for "a tenant validator" do
|
54
|
-
context "within a client context" do
|
55
|
-
before { Mongoid::Multitenancy.current_tenant = client }
|
56
|
-
|
57
|
-
context "with the client id" do
|
58
|
-
before { item.client = client }
|
59
|
-
|
60
|
-
it "should be valid" do
|
61
|
-
item.should be_valid
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context "with another client id" do
|
66
|
-
before { item.client = another_client }
|
67
|
-
|
68
|
-
it "should be invalid" do
|
69
|
-
item.should_not be_valid
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
45
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
context "with the client id" do
|
78
|
-
before { item.client = client }
|
79
|
-
|
80
|
-
it "should be valid" do
|
81
|
-
item.should be_valid
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
context "with another client id" do
|
86
|
-
before { item.client = another_client }
|
87
|
-
|
88
|
-
it "should be valid" do
|
89
|
-
item.should be_valid
|
90
|
-
end
|
91
|
-
end
|
46
|
+
config.after(:each) do
|
47
|
+
Mongoid::Multitenancy.current_tenant = nil
|
92
48
|
end
|
93
49
|
end
|