mongoid-multitenancy-forked 1.0.1
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 +21 -0
- data/.rspec +3 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +56 -0
- data/Gemfile +15 -0
- data/LICENSE.TXT +20 -0
- data/README.md +284 -0
- data/Rakefile +8 -0
- data/gemfiles/Gemfile.mongoid-6 +14 -0
- data/gemfiles/Gemfile.mongoid-7 +14 -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/lib/mongoid/multitenancy.rb +34 -0
- data/lib/mongoid-multitenancy-forked.rb +1 -0
- data/mongoid-multitenancy-forked.gemspec +19 -0
- data/spec/immutable_spec.rb +46 -0
- data/spec/indexable_spec.rb +70 -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 +61 -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 +125 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Multitenancy
|
3
|
+
# Validates whether or not a field is unique against the documents in the
|
4
|
+
# database.
|
5
|
+
#
|
6
|
+
# @example Define the tenant uniqueness validator.
|
7
|
+
#
|
8
|
+
# class Person
|
9
|
+
# include Mongoid::Document
|
10
|
+
# include Mongoid::Multitenancy::Document
|
11
|
+
# field :title
|
12
|
+
# tenant :client
|
13
|
+
#
|
14
|
+
# validates_tenant_uniqueness_of :title
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# It is also possible to limit the uniqueness constraint to a set of
|
18
|
+
# records matching certain conditions:
|
19
|
+
# class Person
|
20
|
+
# include Mongoid::Document
|
21
|
+
# include Mongoid::Multitenancy::Document
|
22
|
+
# field :title
|
23
|
+
# field :active, type: Boolean
|
24
|
+
# tenant :client
|
25
|
+
#
|
26
|
+
# validates_tenant_uniqueness_of :title, conditions: -> {where(active: true)}
|
27
|
+
# end
|
28
|
+
class TenantUniquenessValidator < Mongoid::Validatable::UniquenessValidator
|
29
|
+
# Validate a tenant root document.
|
30
|
+
def validate_root(document, attribute, value)
|
31
|
+
klass = document.class
|
32
|
+
|
33
|
+
while klass.superclass.respond_to?(:validators) && klass.superclass.validators.include?(self)
|
34
|
+
klass = klass.superclass
|
35
|
+
end
|
36
|
+
criteria = create_criteria(klass, document, attribute, value)
|
37
|
+
|
38
|
+
# <<Add the tenant Criteria>>
|
39
|
+
criteria = with_tenant_criterion(criteria, klass, document)
|
40
|
+
criteria = criteria.merge(options[:conditions].call) if options[:conditions]
|
41
|
+
|
42
|
+
if criteria.read(mode: :primary).exists?
|
43
|
+
add_error(document, attribute, value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add the scope criteria for a tenant model criteria.
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
def with_tenant_criterion(criteria, base, document)
|
51
|
+
item = base.tenant_field.to_sym
|
52
|
+
name = document.database_field_name(item)
|
53
|
+
tenant_value = document.attributes[name]
|
54
|
+
|
55
|
+
if document.class.tenant_options[:optional] && !options[:exclude_shared]
|
56
|
+
if tenant_value
|
57
|
+
criteria = criteria.where(:"#{item}".in => [tenant_value, nil])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
criteria = criteria.where(item => tenant_value)
|
61
|
+
end
|
62
|
+
|
63
|
+
criteria
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
require 'mongoid/multitenancy/document'
|
3
|
+
require 'mongoid/multitenancy/version'
|
4
|
+
require 'mongoid/multitenancy/validators/tenancy'
|
5
|
+
require 'mongoid/multitenancy/validators/tenant_uniqueness'
|
6
|
+
|
7
|
+
module Mongoid
|
8
|
+
module Multitenancy
|
9
|
+
class << self
|
10
|
+
# Set the current tenant. Make it Thread aware
|
11
|
+
def current_tenant=(tenant)
|
12
|
+
Thread.current[:current_tenant] = tenant
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the current tenant
|
16
|
+
def current_tenant
|
17
|
+
Thread.current[:current_tenant]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Affects a tenant temporary for a block execution
|
21
|
+
def with_tenant(tenant, &block)
|
22
|
+
raise ArgumentError, 'block required' if block.nil?
|
23
|
+
|
24
|
+
begin
|
25
|
+
old_tenant = current_tenant
|
26
|
+
self.current_tenant = tenant
|
27
|
+
yield
|
28
|
+
ensure
|
29
|
+
self.current_tenant = old_tenant
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'mongoid/multitenancy'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/mongoid/multitenancy/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['Aymeric Brisse']
|
6
|
+
gem.email = ['aymeric.brisse@mperfect-memory.com']
|
7
|
+
gem.description = 'MultiTenancy with Mongoid - This is a fork for mongoid-multitenancy just to allow mongoid version < 10'
|
8
|
+
gem.summary = 'Support of a multi-tenant database with Mongoid'
|
9
|
+
gem.homepage = 'https://github.com/PerfectMemory/mongoid-multitenancy'
|
10
|
+
gem.license = 'MIT'
|
11
|
+
gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = 'mongoid-multitenancy-forked'
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.version = Mongoid::Multitenancy::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency('mongoid', '>= 6', '< 10')
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Immutable 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
|
+
Immutable.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 not valid' do
|
41
|
+
item.tenant = another_client
|
42
|
+
expect(item).not_to be_valid
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'tenant' 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 'tenant full_indexes option' do
|
13
|
+
context 'without index option' do
|
14
|
+
it 'does not create an index' do
|
15
|
+
expect(IndexableWithoutIndex).not_to have_index_for(tenant_id: 1)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with index: false' do
|
20
|
+
it 'does not create an index' do
|
21
|
+
expect(IndexableWithIndexFalse).not_to have_index_for(tenant_id: 1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with index: true' do
|
26
|
+
it 'creates an index' do
|
27
|
+
expect(IndexableWithIndexTrue).to have_index_for(tenant_id: 1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'index full_index option' do
|
33
|
+
context 'without tenant full_indexes option specified' do
|
34
|
+
it 'adds the tenant field on each index' do
|
35
|
+
expect(IndexableWithoutFullIndexes).to have_index_for(tenant_id: 1, title: 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'adds the tenant field on the index with full_index: true' do
|
39
|
+
expect(IndexableWithoutFullIndexes).to have_index_for(tenant_id: 1, name: 1)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'does not add the tenant field on the index with full_index: false' do
|
43
|
+
expect(IndexableWithoutFullIndexes).not_to have_index_for(tenant_id: 1, slug: 1)
|
44
|
+
expect(IndexableWithoutFullIndexes).to have_index_for(slug: 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with full_indexes: true' do
|
49
|
+
it 'adds the tenant field on each index' do
|
50
|
+
expect(IndexableWithFullIndexesTrue).to have_index_for(tenant_id: 1, title: 1)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not add the tenant field on the index with full_index: false' do
|
54
|
+
expect(IndexableWithFullIndexesTrue).not_to have_index_for(tenant_id: 1, name: 1)
|
55
|
+
expect(IndexableWithFullIndexesTrue).to have_index_for(name: 1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with full_indexes: false' do
|
60
|
+
it 'does not add the tenant field on each index' do
|
61
|
+
expect(IndexableWithFullIndexesFalse).not_to have_index_for(tenant_id: 1, title: 1)
|
62
|
+
expect(IndexableWithFullIndexesFalse).to have_index_for(title: 1)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'does add the tenant field on the index with full_index: true' do
|
66
|
+
expect(IndexableWithFullIndexesFalse).to have_index_for(tenant_id: 1, name: 1)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -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,61 @@
|
|
1
|
+
class IndexableWithoutIndex
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant :tenant, class_name: 'Account'
|
6
|
+
end
|
7
|
+
|
8
|
+
class IndexableWithIndexTrue
|
9
|
+
include Mongoid::Document
|
10
|
+
include Mongoid::Multitenancy::Document
|
11
|
+
|
12
|
+
tenant :tenant, class_name: 'Account', index: true
|
13
|
+
end
|
14
|
+
|
15
|
+
class IndexableWithIndexFalse
|
16
|
+
include Mongoid::Document
|
17
|
+
include Mongoid::Multitenancy::Document
|
18
|
+
|
19
|
+
tenant :tenant, class_name: 'Account', index: false
|
20
|
+
end
|
21
|
+
|
22
|
+
class IndexableWithoutFullIndexes
|
23
|
+
include Mongoid::Document
|
24
|
+
include Mongoid::Multitenancy::Document
|
25
|
+
|
26
|
+
field :title, type: String
|
27
|
+
field :name, type: String
|
28
|
+
field :slug, type: String
|
29
|
+
|
30
|
+
tenant :tenant, class_name: 'Account'
|
31
|
+
|
32
|
+
index(title: 1)
|
33
|
+
index({ name: 1 }, { full_index: true })
|
34
|
+
index({ slug: 1 }, { full_index: false })
|
35
|
+
end
|
36
|
+
|
37
|
+
class IndexableWithFullIndexesFalse
|
38
|
+
include Mongoid::Document
|
39
|
+
include Mongoid::Multitenancy::Document
|
40
|
+
|
41
|
+
field :title, type: String
|
42
|
+
field :name, type: String
|
43
|
+
|
44
|
+
tenant :tenant, class_name: 'Account', full_indexes: false
|
45
|
+
|
46
|
+
index(title: 1)
|
47
|
+
index({ name: 1 }, { full_index: true })
|
48
|
+
end
|
49
|
+
|
50
|
+
class IndexableWithFullIndexesTrue
|
51
|
+
include Mongoid::Document
|
52
|
+
include Mongoid::Multitenancy::Document
|
53
|
+
|
54
|
+
field :title, type: String
|
55
|
+
field :name, type: String
|
56
|
+
|
57
|
+
tenant :tenant, class_name: 'Account', full_indexes: true
|
58
|
+
|
59
|
+
index(title: 1)
|
60
|
+
index({ name: 1 }, { full_index: false })
|
61
|
+
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
|