mongoid-multitenancy 1.1.3 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30fa52034535ce4524481877d5b9e048e1eeeaa5
4
- data.tar.gz: 533f4f95ecb750443629027cac6d0dd9edc6bb73
3
+ metadata.gz: 57b6a36dd90e26ab59298efdd32bfeb5b92a1bfd
4
+ data.tar.gz: da726e93d69c677784b0bb5213d21bda3a77af3b
5
5
  SHA512:
6
- metadata.gz: efb3239aa595fe974954364f1b8b7cf2b0bb061d87dac50166294f54a219ed97b68504deead534086576016e840d38b125612a64d12a429d3b37c19ef90deb6a
7
- data.tar.gz: f3a64574e2ef09ade685ab061806bd37885286ead3efe20d884887d14e42ab748e712a1635b9fc2724aa6bb520d614684e70b973bf4952b2866bad396e2125fd
6
+ metadata.gz: b11cda4238d5ef849b59ce910c70136692e04680c764159c128cf38eea5fd89851e8d9d728a3773edbf27ed0013d9fbc2e2777babe2b977c4bcab160198ecca2
7
+ data.tar.gz: bf624d27f91d4ac108f811445eaa9fbbb4837e88427cc4a5eb7d810c9adbb19f6310f7a94ac84592560f371ad9ed666999498a7395cc562f495d845be724880e
@@ -1,13 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
- - 2.1.0
5
- - 2.2.0
3
+ - 2.2.2
6
4
  - 2.3.0
7
- - jruby
5
+ - 2.4.1
8
6
  gemfile:
9
- - gemfiles/Gemfile.mongoid-4.0
10
- - gemfiles/Gemfile.mongoid-5.0
7
+ - gemfiles/Gemfile.mongoid-6
8
+ - gemfiles/Gemfile.mongoid-7
11
9
  - Gemfile
12
10
  services:
13
11
  - mongodb
@@ -1,3 +1,36 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [2.0.3] - 2020-06-25
8
+ ### Fixed
9
+
10
+ * Full Support of mongoid 7
11
+
12
+ ## [2.0.2] - 2018-08-23
13
+ ### Added
14
+
15
+ * Support of mongoid 7
16
+
17
+ ## [2.0.1] - 2017-12-14
18
+ ### Changed
19
+
20
+ * Add ensure block in method with_tenant
21
+
22
+ ## [2.0] - 2017-07-21
23
+ ### New Features
24
+
25
+ * Add support for mongoid 6
26
+ * Remove support for mongoid 4 & 5
27
+
28
+ ## 1.2
29
+
30
+ ### New Features
31
+
32
+ * Add *exclude_shared* option for the TenantUniquenessValidator
33
+
1
34
  ## 1.1
2
35
 
3
36
  ### New Features
@@ -12,7 +45,7 @@
12
45
 
13
46
  ### New Features
14
47
 
15
- * Adds support for mongoid 5
48
+ * Add support for mongoid 5
16
49
 
17
50
  ### Major Changes (Backwards Incompatible)
18
51
 
data/Gemfile CHANGED
@@ -1,15 +1,13 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'mongoid', '~> 5.0'
4
-
5
- gem 'rake', '~> 10.0'
3
+ gem 'rake'
6
4
 
7
5
  group :test do
8
- gem 'database_cleaner', github: 'DatabaseCleaner/database_cleaner', ref: '1cab518'
6
+ gem 'database_cleaner'
9
7
  gem 'coveralls', require: false
10
8
  gem 'rspec', '~> 3.1'
11
- gem 'yard', '~> 0.8'
12
- gem 'mongoid-rspec', '~> 3.0'
9
+ gem 'yard'
10
+ gem 'mongoid-rspec', git: 'https://github.com/mongoid-rspec/mongoid-rspec.git'
13
11
  gem 'rubocop', require: false
14
12
  end
15
13
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # mongoid-multitenancy [![Build Status](https://travis-ci.org/PerfectMemory/mongoid-multitenancy.png?branch=master)](https://travis-ci.org/PerfectMemory/mongoid-multitenancy) [![Coverage Status](https://coveralls.io/repos/PerfectMemory/mongoid-multitenancy/badge.svg?branch=master&service=github)](https://coveralls.io/github/PerfectMemory/mongoid-multitenancy?branch=master) [![Code Climate](https://codeclimate.com/github/PerfectMemory/mongoid-multitenancy.png)](https://codeclimate.com/github/PerfectMemory/mongoid-multitenancy) [![Dependency Status](https://gemnasium.com/PerfectMemory/mongoid-multitenancy.png)](https://gemnasium.com/PerfectMemory/mongoid-multitenancy)
1
+ # mongoid-multitenancy [![Build Status](https://api.travis-ci.org/PerfectMemory/mongoid-multitenancy.png?branch=master)](https://travis-ci.org/PerfectMemory/mongoid-multitenancy) [![Coverage Status](https://coveralls.io/repos/github/PerfectMemory/mongoid-multitenancy/badge.svg?branch=master)](https://coveralls.io/github/PerfectMemory/mongoid-multitenancy?branch=master) [![Code Climate](https://codeclimate.com/github/PerfectMemory/mongoid-multitenancy.png)](https://codeclimate.com/github/PerfectMemory/mongoid-multitenancy)
2
2
 
3
3
  mongoid-multitenancy adds the ability to scope [Mongoid](https://github.com/mongoid/mongoid) models to a tenant in a **shared database strategy**. Tenants are represented by a tenant model, such as `Client`. mongoid-multitenancy will help you set the current tenant on each request and ensures that all 'tenant models' are always properly scoped to the current tenant: when viewing, searching and creating.
4
4
 
@@ -12,12 +12,17 @@ In addition, mongoid-multitenancy:
12
12
  * is thread safe
13
13
  * redefines some mongoid functions like `index`, `validates_with` and `delete_all` to take in account the multitenancy.
14
14
 
15
+ Compatibility
16
+ ===============
17
+
18
+ mongoid-multitenancy 2.0 is compatible with mongoid 6/7. For mongoid 4/5 compatiblity, use mongoid-multitenancy 1.2.
19
+
15
20
  Installation
16
21
  ===============
17
22
 
18
23
  Add this line to your application's Gemfile:
19
24
 
20
- gem 'mongoid-multitenancy'
25
+ gem 'mongoid-multitenancy', '~> 2.0'
21
26
 
22
27
  And then execute:
23
28
 
@@ -74,7 +79,7 @@ class Article
74
79
  include Mongoid::Document
75
80
  include Mongoid::Multitenancy::Document
76
81
 
77
- tenant(:client)
82
+ tenant(:tenant)
78
83
 
79
84
  field :title, :type => String
80
85
  end
@@ -85,10 +90,14 @@ The association passed to the `tenant` function must be valid.
85
90
 
86
91
  `tenant` accepts several options:
87
92
 
88
- * :optional : set to true when the tenant is optional (default value is `false`)
89
- * :immutable : set to true when the tenant field is immutable (default value is `true`)
90
- * :full_indexes : set to true to add the tenant field automatically to all the indexes (default value is `true`)
91
- * :class_name, etc. : all the other options will be passed to the mongoid relation (belongs_to)
93
+ | Option | Default | Description |
94
+ | ------------- | ------------- | ------------- |
95
+ | :optional | false | set to true when the tenant is optional |
96
+ | :immutable | true | set to true when the tenant field is immutable |
97
+ | :full_indexes | true | set to true to add the tenant field automatically to all the indexes |
98
+ | :index | false | set to true to define an index for the tenant field |
99
+ | :scopes | true | set to true to define scopes :shared and :unshared |
100
+ | :class_name, etc. | | all the other options will be passed to the mongoid relation (belongs_to) |
92
101
 
93
102
  Some examples to illustrate this behavior:
94
103
 
@@ -97,15 +106,15 @@ Some examples to illustrate this behavior:
97
106
  Mongoid::Multitenancy.current_tenant = Client.find_by(:name => 'Perfect Memory') # => <#Client _id:50ca04b86c82bfc125000025, :name: "Perfect Memory">
98
107
 
99
108
  # All searches are scoped by the tenant, the following searches will only return objects belonging to the current client.
100
- Article.all # => all articles where client_id => 50ca04b86c82bfc125000025
109
+ Article.all # => all articles where tenant_id => 50ca04b86c82bfc125000025
101
110
 
102
111
  # New objects are scoped to the current tenant
103
112
  article = Article.new(:title => 'New blog')
104
- article.save # => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', client_id: 50ca04b86c82bfc125000025>
113
+ article.save # => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', tenant_id: 50ca04b86c82bfc125000025>
105
114
 
106
115
  # It can make the tenant field immutable once it is persisted to avoid inconsistency
107
116
  article.persisted? # => true
108
- article.client = another_client
117
+ article.tenant = another_client
109
118
  article.valid? # => false
110
119
  ```
111
120
 
@@ -120,21 +129,21 @@ class Article
120
129
  include Mongoid::Document
121
130
  include Mongoid::Multitenancy::Document
122
131
 
123
- tenant(:client, optional: true)
132
+ tenant(:tenant, optional: true)
124
133
 
125
134
  field :title, :type => String
126
135
  end
127
136
 
128
137
  Mongoid::Multitenancy.with_tenant(client_instance) do
129
- Article.all # => all articles where client_id.in [50ca04b86c82bfc125000025, nil]
138
+ Article.all # => all articles where tenant_id.in [50ca04b86c82bfc125000025, nil]
130
139
  article = Article.new(:title => 'New article')
131
- article.save # => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', client_id: 50ca04b86c82bfc125000025>
140
+ article.save # => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', tenant_id: 50ca04b86c82bfc125000025>
132
141
 
133
142
  # tenant needs to be set manually to nil
134
- article = Article.new(:title => 'New article', :client => nil)
135
- article.save # => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', client_id: 50ca04b86c82bfc125000025>
143
+ article = Article.new(:title => 'New article', :tenant => nil)
144
+ article.save # => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', tenant_id: 50ca04b86c82bfc125000025>
136
145
  article.tenant = nil
137
- article.save => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', client_id: nil>
146
+ article.save => <#Article _id: 50ca04b86c82bfc125000044, title: 'New blog', tenant_id: nil>
138
147
  end
139
148
  ```
140
149
 
@@ -173,7 +182,7 @@ class Article
173
182
  include Mongoid::Document
174
183
  include Mongoid::Multitenancy::Document
175
184
 
176
- tenant :client
185
+ tenant :tenant
177
186
 
178
187
  field :slug
179
188
 
@@ -181,19 +190,19 @@ class Article
181
190
  end
182
191
  ```
183
192
 
184
- * When used with an *optional* tenant, the uniqueness constraint is not scoped if the item is shared, but is
185
- scoped to the client new item otherwise. Note that a private item cannot have the the value if a shared item
186
- already uses it.
193
+ * When used with an *optional* tenant, the uniqueness constraint by default is not scoped if the item is shared, but is
194
+ scoped to the client new item otherwise. Note that by default in that case a private item cannot have a value if a shared item
195
+ already uses it. You can change that behaviour by setting the option `exclude_shared` to `true`.
187
196
 
188
197
  In the following case, 2 private articles can have the same slug if they belongs to 2 different clients. But if a shared
189
- article has the slug "slugA", no client will be able to use that slug again, like a standard validates_uniqueness_of does.
198
+ article has the slug "slugA", no client will be able to use that slug again, like a standard `validates_uniqueness_of` does.
190
199
 
191
200
  ```ruby
192
201
  class Article
193
202
  include Mongoid::Document
194
203
  include Mongoid::Multitenancy::Document
195
204
 
196
- tenant :client, optional: true
205
+ tenant :tenant, optional: true
197
206
 
198
207
  field :slug
199
208
 
@@ -201,6 +210,22 @@ class Article
201
210
  end
202
211
  ```
203
212
 
213
+ In the following case, 2 private articles can have the same slug if they belongs to 2 different clients even if a shared
214
+ article already uses that same slug, like a `validates_uniqueness_of scope: :tenant` does.
215
+
216
+ ```ruby
217
+ class Article
218
+ include Mongoid::Document
219
+ include Mongoid::Multitenancy::Document
220
+
221
+ tenant :tenant, optional: true
222
+
223
+ field :slug
224
+
225
+ validates_tenant_uniqueness_of :slug, exclude_shared: true
226
+ end
227
+ ```
228
+
204
229
  Mongoid indexes
205
230
  -------------------
206
231
 
@@ -210,14 +235,14 @@ To create a single index on the tenant field, you can use the option `index: tru
210
235
 
211
236
  On the example below, only one indexe will be created:
212
237
 
213
- * { 'title_id' => 1, 'client_id' => 1 }
238
+ * { 'title_id' => 1, 'tenant_id' => 1 }
214
239
 
215
240
  ```ruby
216
241
  class Article
217
242
  include Mongoid::Document
218
243
  include Mongoid::Multitenancy::Document
219
244
 
220
- tenant :client, full_indexes: true
245
+ tenant :tenant, full_indexes: true
221
246
 
222
247
  field :title
223
248
 
@@ -227,7 +252,7 @@ end
227
252
 
228
253
  On the example below, 2 indexes will be created:
229
254
 
230
- * { 'client_id' => 1 }
255
+ * { 'tenant_id' => 1 }
231
256
  * { 'title_id' => 1 }
232
257
 
233
258
  ```ruby
@@ -235,7 +260,7 @@ class Article
235
260
  include Mongoid::Document
236
261
  include Mongoid::Multitenancy::Document
237
262
 
238
- tenant :client, index: true
263
+ tenant :tenant, index: true
239
264
 
240
265
  field :title
241
266
 
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'mongoid', '~> 6.0'
4
+
5
+ gem 'rake'
6
+
7
+ group :test do
8
+ gem 'database_cleaner'
9
+ gem 'coveralls', require: false
10
+ gem 'rspec', '~> 3.1'
11
+ gem 'yard'
12
+ gem 'mongoid-rspec', git: 'https://github.com/mongoid-rspec/mongoid-rspec.git'
13
+ gem 'rubocop', require: false
14
+ end
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'mongoid', '~> 7.0'
4
+
5
+ gem 'rake'
6
+
7
+ group :test do
8
+ gem 'database_cleaner'
9
+ gem 'coveralls', require: false
10
+ gem 'rspec', '~> 3.1'
11
+ gem 'yard'
12
+ gem 'mongoid-rspec', git: 'https://github.com/mongoid-rspec/mongoid-rspec.git'
13
+ gem 'rubocop', require: false
14
+ end
@@ -7,7 +7,6 @@ require 'mongoid/multitenancy/validators/tenant_uniqueness'
7
7
  module Mongoid
8
8
  module Multitenancy
9
9
  class << self
10
-
11
10
  # Set the current tenant. Make it Thread aware
12
11
  def current_tenant=(tenant)
13
12
  Thread.current[:current_tenant] = tenant
@@ -22,11 +21,13 @@ module Mongoid
22
21
  def with_tenant(tenant, &block)
23
22
  raise ArgumentError, 'block required' if block.nil?
24
23
 
25
- old_tenant = self.current_tenant
26
- self.current_tenant = tenant
27
- result = block.call
28
- self.current_tenant = old_tenant
29
- result
24
+ begin
25
+ old_tenant = current_tenant
26
+ self.current_tenant = tenant
27
+ yield
28
+ ensure
29
+ self.current_tenant = old_tenant
30
+ end
30
31
  end
31
32
  end
32
33
  end
@@ -7,7 +7,7 @@ module Mongoid
7
7
  attr_accessor :tenant_field, :tenant_options
8
8
 
9
9
  # List of authorized options
10
- MULTITENANCY_OPTIONS = [:optional, :immutable, :full_indexes, :index]
10
+ MULTITENANCY_OPTIONS = [:optional, :immutable, :full_indexes, :index, :scopes].freeze
11
11
 
12
12
  # Defines the tenant field for the document.
13
13
  #
@@ -24,10 +24,13 @@ module Mongoid
24
24
  # wil raise an Exception.
25
25
  # @option options [ Boolean ] :optional If true allow the document
26
26
  # to be shared among all the tenants.
27
- #
27
+ # @option options [ Boolean ] :index If true build an index for
28
+ # the tenant field itself.
29
+ # @option options [ Boolean ] :scopes If true create scopes :shared
30
+ # and :unshared.
28
31
  # @return [ Field ] The generated field
29
32
  def tenant(association = :account, options = {})
30
- options = { full_indexes: true, immutable: true }.merge!(options)
33
+ options = { full_indexes: true, immutable: true, scopes: true }.merge!(options)
31
34
  assoc_options, multitenant_options = build_options(options)
32
35
 
33
36
  # Setup the association between the class and the tenant class
@@ -40,7 +43,7 @@ module Mongoid
40
43
  # Validates the tenant field
41
44
  validates_tenancy_of tenant_field, multitenant_options
42
45
 
43
- define_scopes
46
+ define_scopes if multitenant_options[:scopes]
44
47
  define_initializer association
45
48
  define_inherited association, options
46
49
  define_index if multitenant_options[:index]
@@ -92,7 +95,7 @@ module Mongoid
92
95
  end
93
96
 
94
97
  # Redefine 'delete_all' to take in account the default scope
95
- def delete_all(conditions = nil)
98
+ def delete_all(conditions = {})
96
99
  scoped.where(conditions).delete
97
100
  end
98
101
 
@@ -106,6 +109,7 @@ module Mongoid
106
109
  options.each do |k, v|
107
110
  if MULTITENANCY_OPTIONS.include?(k)
108
111
  multitenant_options[k] = v
112
+ assoc_options[k] = v if k == :optional
109
113
  else
110
114
  assoc_options[k] = v
111
115
  end
@@ -131,7 +135,7 @@ module Mongoid
131
135
  # Define the inherited method
132
136
  def define_inherited(association, options)
133
137
  define_singleton_method(:inherited) do |child|
134
- child.tenant association, options
138
+ child.tenant association, options.merge(scopes: false)
135
139
  super(child)
136
140
  end
137
141
  end
@@ -150,7 +154,7 @@ module Mongoid
150
154
  where(tenant_field => tenant_id)
151
155
  end
152
156
  else
153
- where(nil)
157
+ all
154
158
  end
155
159
  }
156
160
 
@@ -16,18 +16,18 @@ module Mongoid
16
16
  def validate_each(object, attribute, value)
17
17
  # Immutable Check
18
18
  if options[:immutable]
19
- if object.send(:attribute_changed?, attribute) and object.send(:attribute_was, attribute)
19
+ if object.send(:attribute_changed?, attribute) && object.send(:attribute_was, attribute)
20
20
  object.errors.add(attribute, 'is immutable and cannot be updated')
21
21
  end
22
22
  end
23
23
 
24
24
  # Ownership check
25
- if value and Mongoid::Multitenancy.current_tenant and value != Mongoid::Multitenancy.current_tenant.id
26
- object.errors.add(attribute, "not authorized")
25
+ if value && Mongoid::Multitenancy.current_tenant && value != Mongoid::Multitenancy.current_tenant.id
26
+ object.errors.add(attribute, 'not authorized')
27
27
  end
28
28
 
29
29
  # Optional Check
30
- if !options[:optional] and value.nil?
30
+ if !options[:optional] && value.nil?
31
31
  object.errors.add(attribute, 'is mandatory')
32
32
  end
33
33
  end
@@ -39,14 +39,8 @@ module Mongoid
39
39
  criteria = with_tenant_criterion(criteria, klass, document)
40
40
  criteria = criteria.merge(options[:conditions].call) if options[:conditions]
41
41
 
42
- if Mongoid::VERSION.start_with?('4')
43
- if criteria.with(persistence_options(criteria)).exists?
44
- add_error(document, attribute, value)
45
- end
46
- else
47
- if criteria.with(criteria.persistence_options).read(mode: :primary).exists?
48
- add_error(document, attribute, value)
49
- end
42
+ if criteria.read(mode: :primary).exists?
43
+ add_error(document, attribute, value)
50
44
  end
51
45
  end
52
46
 
@@ -58,8 +52,8 @@ module Mongoid
58
52
  name = document.database_field_name(item)
59
53
  tenant_value = document.attributes[name]
60
54
 
61
- if document.class.tenant_options[:optional]
62
- if document.attributes[name]
55
+ if document.class.tenant_options[:optional] && !options[:exclude_shared]
56
+ if tenant_value
63
57
  criteria = criteria.where(:"#{item}".in => [tenant_value, nil])
64
58
  end
65
59
  else
@@ -1,6 +1,6 @@
1
1
  module Mongoid
2
2
  module Multitenancy
3
3
  # Version
4
- VERSION = '1.1.3'
4
+ VERSION = '2.0.3'.freeze
5
5
  end
6
6
  end
@@ -8,12 +8,12 @@ Gem::Specification.new do |gem|
8
8
  gem.summary = 'Support of a multi-tenant database with Mongoid'
9
9
  gem.homepage = 'https://github.com/PerfectMemory/mongoid-multitenancy'
10
10
  gem.license = 'MIT'
11
- gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
11
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
13
13
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
14
  gem.name = 'mongoid-multitenancy'
15
15
  gem.require_paths = ['lib']
16
16
  gem.version = Mongoid::Multitenancy::VERSION
17
17
 
18
- gem.add_dependency('mongoid', '>= 4.0')
18
+ gem.add_dependency('mongoid', '>= 6', '< 8')
19
19
  end
@@ -38,7 +38,7 @@ describe Immutable do
38
38
  end
39
39
 
40
40
  it 'is not valid' do
41
- item.client = another_client
41
+ item.tenant = another_client
42
42
  expect(item).not_to be_valid
43
43
  end
44
44
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'tenant' do
4
-
5
4
  let(:client) do
6
5
  Account.create!(name: 'client')
7
6
  end
@@ -12,26 +11,25 @@ describe 'tenant' do
12
11
 
13
12
  context 'without index: true' do
14
13
  it 'does not create an index' do
15
- expect(Immutable).not_to have_index_for(:client_id => 1)
14
+ expect(Immutable).not_to have_index_for(tenant_id: 1)
16
15
  end
17
16
  end
18
17
 
19
18
  context 'with index: true' do
20
19
  it 'creates an index' do
21
- expect(Indexable).to have_index_for(:client_id => 1)
20
+ expect(Indexable).to have_index_for(tenant_id: 1)
22
21
  end
23
22
  end
24
23
 
25
24
  context 'with full_indexes: true' do
26
25
  it 'add the tenant field on each index' do
27
- expect(Immutable).to have_index_for(:client_id => 1, title: 1)
26
+ expect(Immutable).to have_index_for(tenant_id: 1, title: 1)
28
27
  end
29
28
  end
30
29
 
31
30
  context 'with full_indexes: false' do
32
31
  it 'does not add the tenant field on each index' do
33
- expect(Indexable).not_to have_index_for(:client_id => 1, title: 1)
32
+ expect(Indexable).not_to have_index_for(tenant_id: 1, title: 1)
34
33
  end
35
34
  end
36
-
37
35
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mandatory do
4
-
5
4
  let(:client) do
6
5
  Account.create!(name: 'client')
7
6
  end
@@ -17,6 +16,18 @@ describe Mandatory do
17
16
  it_behaves_like 'a tenantable model'
18
17
  it { is_expected.to validate_tenant_uniqueness_of(:slug) }
19
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
+
20
31
  describe '.default_scope' do
21
32
  before do
22
33
  Mongoid::Multitenancy.with_tenant(client) { @itemX = Mandatory.create!(title: 'title X', slug: 'article-x') }
@@ -1,5 +1,5 @@
1
1
  class Account
2
2
  include Mongoid::Document
3
3
 
4
- field :name, :type => String
4
+ field :name, type: String
5
5
  end
@@ -2,14 +2,14 @@ class Immutable
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant(:client, class_name: 'Account', immutable: true)
5
+ tenant(:tenant, class_name: 'Account', immutable: true)
6
6
 
7
- field :slug, :type => String
8
- field :title, :type => String
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({ title: 1 })
14
+ index(title: 1)
15
15
  end
@@ -4,7 +4,7 @@ class Indexable
4
4
 
5
5
  field :title, type: String
6
6
 
7
- tenant :client, class_name: 'Account', index: true, full_indexes: false
7
+ tenant :tenant, class_name: 'Account', index: true, full_indexes: false
8
8
 
9
- index({ title: 1 })
9
+ index(title: 1)
10
10
  end
@@ -2,14 +2,14 @@ class Mandatory
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant(:client, class_name: 'Account')
5
+ tenant(:tenant, class_name: 'Account')
6
6
 
7
7
  field :slug, type: String
8
- field :title, 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({ title: 1 })
14
+ index(title: 1)
15
15
  end
@@ -2,14 +2,14 @@ class Mutable
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant :client, class_name: 'Account', immutable: false, optional: false
5
+ tenant :tenant, class_name: 'Account', immutable: false, optional: false
6
6
 
7
- field :slug, :type => String
8
- field :title, :type => String
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({ title: 1 })
14
+ index(title: 1)
15
15
  end
@@ -1,9 +1,9 @@
1
1
  require 'models/mutable'
2
2
 
3
3
  class MutableChild < Mutable
4
- field :random, type: String
4
+ field :random, type: String
5
5
  end
6
6
 
7
7
  class AnotherMutableChild < Mutable
8
- field :random, type: String
9
- end
8
+ field :random, type: String
9
+ end
@@ -0,0 +1,11 @@
1
+ class NoScopable
2
+ include Mongoid::Document
3
+ include Mongoid::Multitenancy::Document
4
+
5
+ tenant :tenant, class_name: 'Account', scopes: false
6
+
7
+ field :slug, type: String
8
+ field :title, type: String
9
+
10
+ index(title: 1)
11
+ end
@@ -2,7 +2,7 @@ class Optional
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant(:client, class_name: 'Account', optional: true)
5
+ tenant(:tenant, class_name: 'Account', optional: true)
6
6
 
7
7
  field :slug, type: String
8
8
  field :title, type: String
@@ -11,5 +11,5 @@ class Optional
11
11
  validates_presence_of :slug
12
12
  validates_presence_of :title
13
13
 
14
- index({ title: 1 })
14
+ index(title: 1)
15
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
@@ -21,8 +21,17 @@ describe Mongoid::Multitenancy do
21
21
  end
22
22
 
23
23
  it 'restores the current tenant after the block' do
24
- Mongoid::Multitenancy.with_tenant(another_client) do ; end
24
+ Mongoid::Multitenancy.with_tenant(another_client) { ; }
25
25
  expect(Mongoid::Multitenancy.current_tenant).to eq client
26
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
27
36
  end
28
37
  end
@@ -38,10 +38,9 @@ describe MutableChild do
38
38
  end
39
39
 
40
40
  it 'is valid' do
41
- item.client = another_client
41
+ item.tenant = another_client
42
42
  expect(item).to be_valid
43
43
  end
44
44
  end
45
45
  end
46
-
47
46
  end
@@ -42,7 +42,7 @@ describe Mutable do
42
42
  end
43
43
 
44
44
  it 'is valid' do
45
- item.client = another_client
45
+ item.tenant = another_client
46
46
  expect(item).to be_valid
47
47
  end
48
48
  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
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Optional do
4
-
5
4
  let(:client) do
6
5
  Account.create!(name: 'client')
7
6
  end
@@ -25,13 +24,13 @@ describe Optional do
25
24
 
26
25
  context 'when persisted' do
27
26
  before do
28
- item.client = nil
27
+ item.tenant = nil
29
28
  item.save!
30
29
  end
31
30
 
32
31
  it 'does not override the client' do
33
32
  item.reload
34
- expect(Optional.last.client).to be_nil
33
+ expect(Optional.last.tenant).to be_nil
35
34
  end
36
35
  end
37
36
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe NoScopable do
4
+ it_behaves_like 'a tenantable model' do
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
+ NoScopable.new(title: 'title X', slug: 'page-x')
15
+ end
16
+ end
17
+
18
+ describe '.shared' do
19
+ it 'is not defined' do
20
+ expect(NoScopable).not_to respond_to(:shared)
21
+ end
22
+ end
23
+
24
+ describe '.unshared' do
25
+ it 'is not defined' do
26
+ expect(NoScopable).not_to respond_to(:unshared)
27
+ end
28
+ end
29
+ end
@@ -15,12 +15,6 @@ require 'mongoid'
15
15
  require 'mongoid-multitenancy'
16
16
  require 'mongoid-rspec'
17
17
 
18
- if Mongoid::VERSION.start_with? '5'
19
- Mongo::Logger.logger.level = ::Logger::FATAL
20
- elsif Mongoid::VERSION.start_with? '4'
21
- Moped.logger = nil
22
- end
23
-
24
18
  require_relative 'support/shared_examples'
25
19
  require_relative 'support/mongoid_matchers'
26
20
 
@@ -30,7 +24,8 @@ Mongoid.configure do |config|
30
24
  config.connect_to 'mongoid_multitenancy'
31
25
  end
32
26
 
33
- Mongoid.logger = nil
27
+ Mongoid.logger.level = Logger::INFO
28
+ Mongo::Logger.logger.level = Logger::INFO
34
29
 
35
30
  RSpec.configure do |config|
36
31
  config.include Mongoid::Matchers
@@ -1,7 +1,6 @@
1
1
  shared_examples_for 'a tenantable model' do
2
-
3
- it { is_expected.to belong_to(:client) }
4
- it { is_expected.to have_index_for(client_id: 1, title: 1) }
2
+ it { is_expected.to belong_to(:tenant) }
3
+ it { is_expected.to have_index_for(tenant_id: 1, title: 1) }
5
4
 
6
5
  describe '#initialize' do
7
6
  context 'within a client context' do
@@ -10,7 +9,7 @@ shared_examples_for 'a tenantable model' do
10
9
  end
11
10
 
12
11
  it 'set the client' do
13
- expect(item.client).to eq client
12
+ expect(item.tenant).to eq client
14
13
  end
15
14
  end
16
15
 
@@ -20,7 +19,7 @@ shared_examples_for 'a tenantable model' do
20
19
  end
21
20
 
22
21
  it 'does not set any client' do
23
- expect(item.client).to be_nil
22
+ expect(item.tenant).to be_nil
24
23
  end
25
24
  end
26
25
  end
@@ -33,7 +32,7 @@ shared_examples_for 'a tenantable model' do
33
32
 
34
33
  context 'with the client id' do
35
34
  before do
36
- item.client = client
35
+ item.tenant = client
37
36
  end
38
37
 
39
38
  it 'is valid' do
@@ -43,7 +42,7 @@ shared_examples_for 'a tenantable model' do
43
42
 
44
43
  context 'with another client id' do
45
44
  before do
46
- item.client = another_client
45
+ item.tenant = another_client
47
46
  end
48
47
 
49
48
  it 'is not valid' do
@@ -59,7 +58,7 @@ shared_examples_for 'a tenantable model' do
59
58
 
60
59
  context 'with the client id' do
61
60
  before do
62
- item.client = client
61
+ item.tenant = client
63
62
  end
64
63
 
65
64
  it 'is valid' do
@@ -69,7 +68,7 @@ shared_examples_for 'a tenantable model' do
69
68
 
70
69
  context 'with another client id' do
71
70
  before do
72
- item.client = another_client
71
+ item.tenant = another_client
73
72
  end
74
73
 
75
74
  it 'is valid' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-multitenancy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aymeric Brisse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-25 00:00:00.000000000 Z
11
+ date: 2020-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '6'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '4.0'
29
+ version: '6'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8'
27
33
  description: MultiTenancy with Mongoid
28
34
  email:
29
35
  - aymeric.brisse@mperfect-memory.com
@@ -39,8 +45,8 @@ files:
39
45
  - LICENSE.TXT
40
46
  - README.md
41
47
  - Rakefile
42
- - gemfiles/Gemfile.mongoid-4.0
43
- - gemfiles/Gemfile.mongoid-5.0
48
+ - gemfiles/Gemfile.mongoid-6
49
+ - gemfiles/Gemfile.mongoid-7
44
50
  - lib/mongoid-multitenancy.rb
45
51
  - lib/mongoid/multitenancy.rb
46
52
  - lib/mongoid/multitenancy/document.rb
@@ -58,11 +64,15 @@ files:
58
64
  - spec/models/mandatory.rb
59
65
  - spec/models/mutable.rb
60
66
  - spec/models/mutable_child.rb
67
+ - spec/models/no_scopable.rb
61
68
  - spec/models/optional.rb
69
+ - spec/models/optional_exclude.rb
62
70
  - spec/mongoid-multitenancy_spec.rb
63
71
  - spec/mutable_child_spec.rb
64
72
  - spec/mutable_spec.rb
73
+ - spec/optional_exclude_spec.rb
65
74
  - spec/optional_spec.rb
75
+ - spec/scopable_spec.rb
66
76
  - spec/spec_helper.rb
67
77
  - spec/support/mongoid_matchers.rb
68
78
  - spec/support/shared_examples.rb
@@ -86,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
96
  version: '0'
87
97
  requirements: []
88
98
  rubyforge_project:
89
- rubygems_version: 2.2.5
99
+ rubygems_version: 2.6.14.4
90
100
  signing_key:
91
101
  specification_version: 4
92
102
  summary: Support of a multi-tenant database with Mongoid
@@ -101,12 +111,15 @@ test_files:
101
111
  - spec/models/mandatory.rb
102
112
  - spec/models/mutable.rb
103
113
  - spec/models/mutable_child.rb
114
+ - spec/models/no_scopable.rb
104
115
  - spec/models/optional.rb
116
+ - spec/models/optional_exclude.rb
105
117
  - spec/mongoid-multitenancy_spec.rb
106
118
  - spec/mutable_child_spec.rb
107
119
  - spec/mutable_spec.rb
120
+ - spec/optional_exclude_spec.rb
108
121
  - spec/optional_spec.rb
122
+ - spec/scopable_spec.rb
109
123
  - spec/spec_helper.rb
110
124
  - spec/support/mongoid_matchers.rb
111
125
  - spec/support/shared_examples.rb
112
- has_rdoc:
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'mongoid', '~> 4.0'
4
-
5
- gem 'rake', '~> 10.0'
6
-
7
- group :test do
8
- gem 'database_cleaner', github: 'DatabaseCleaner/database_cleaner', ref: '1cab518'
9
- gem 'coveralls', :require => false
10
- gem 'rspec', '~> 3.1'
11
- gem 'yard', '~> 0.8'
12
- gem 'mongoid-rspec', '~> 2.1'
13
- end
14
-
15
- # Specify your gem's dependencies in mongoid-multitenancy.gemspec
16
- gemspec :path => '..'
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'mongoid', '~> 5.0'
4
-
5
- gem 'rake', '~> 10.0'
6
-
7
- group :test do
8
- gem 'database_cleaner', github: 'DatabaseCleaner/database_cleaner', ref: '1cab518'
9
- gem 'coveralls', :require => false
10
- gem 'rspec', '~> 3.1'
11
- gem 'yard', '~> 0.8'
12
- gem 'mongoid-rspec', '~> 3.0'
13
- end
14
-
15
- # Specify your gem's dependencies in mongoid-multitenancy.gemspec
16
- gemspec :path => '..'