mongoid-multitenancy 1.1.3 → 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 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 => '..'