mongoid-multitenancy 0.4.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|