rails_multitenant 0.13.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a58f005f75cca12de2a1faaee149d98a0810a64d268e602bc4c64af56047ba95
4
- data.tar.gz: a979bf78f8c98deb80bd71e3bda893cc1d3cc35a7b50b224c7a3dd98c869db2e
3
+ metadata.gz: 7c02cf9f31f24d9691805f12bc6adef3ab888e88485165e4c0650e2b35613f01
4
+ data.tar.gz: 4f72b4851a80747b6ba9d4894ff630d126e01529b7252535c074fca7c0685092
5
5
  SHA512:
6
- metadata.gz: 8375cb4f2c2a0676f1cc8b049ee4b416025840f085bc270f3ace7ecb2d4cf2b32f7715418d0888ce71ed63667ecc33bd722502a04dc3683d71663ece746a53c3
7
- data.tar.gz: 450cb63b8d3b13c8e4fe4d4f2800933ec276faece554d3b5021eda1508f2d8a085282c7fa1e700e6b6aca666dc960a04721fe850d2bd68ee533b7d8420ee175d
6
+ metadata.gz: 92e605eed7bfa4627ae5efb83e821666f689c36ff8b547a94fdd5f1fa5d4efd07d0f93ebe68d8eacc5d77c964921918ecd114359ef0b76205f01705b92a7b432
7
+ data.tar.gz: 9542475a6ae4a1d0e43e65281a4e70440a1879062a51f6130842b4bee6391ef44f009269b913f0440542bf49337ca807541ed908542f6dfbc3cb56aaa62ffa30
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'registry_dependent_on'
4
+
5
+ module RailsMultitenant
6
+ module GlobalContextRegistry
7
+ # This module allows your to have a current, thread-local instance
8
+ # of this class. It currently assumes your class has a zero-arg
9
+ # constructor.
10
+ module Current
11
+ extend ActiveSupport::Concern
12
+
13
+ included do
14
+ class_attribute :default_provider, instance_writer: false
15
+ end
16
+
17
+ module ClassMethods
18
+ def current
19
+ GlobalContextRegistry.fetch(current_registry_obj) { __current_default }
20
+ end
21
+
22
+ def current=(object)
23
+ raise "#{object} is not a #{self}" if object.present? && !object.is_a?(self)
24
+
25
+ GlobalContextRegistry.set(current_registry_obj, object)
26
+ __clear_dependents!
27
+ end
28
+
29
+ def current?
30
+ GlobalContextRegistry.get(current_registry_obj).present?
31
+ end
32
+
33
+ def current!
34
+ current || raise("No current #{name} set")
35
+ end
36
+
37
+ def clear_current!
38
+ GlobalContextRegistry.delete(current_registry_obj)
39
+ end
40
+
41
+ def as_current(object)
42
+ old_object = current if current?
43
+ self.current = object
44
+ yield
45
+ ensure
46
+ self.current = old_object
47
+ end
48
+
49
+ include RegistryDependentOn
50
+
51
+ def provide_default(provider = nil, &block)
52
+ self.default_provider = provider ? provider.to_proc : block
53
+ end
54
+
55
+ private
56
+
57
+ def current_registry_obj
58
+ return @current_registry_obj if @current_registry_obj
59
+
60
+ @current_registry_obj = "#{__key_class.name.underscore}_obj".to_sym
61
+ end
62
+
63
+ def current_registry_default_provider
64
+ "#{__key_class.name.underscore}_default_provider".to_sym
65
+ end
66
+
67
+ def __current_default
68
+ if default_provider
69
+ default = default_provider.call(self)
70
+ raise "#{default} is not a #{self}" if default.present? && !default.is_a?(self)
71
+
72
+ default
73
+ end
74
+ end
75
+
76
+ def __clear_dependents!
77
+ GlobalContextRegistry.send(:dependencies_for, __key_class).each(&:clear_current!)
78
+ end
79
+
80
+ def __key_class
81
+ respond_to?(:base_class) ? base_class : self
82
+ end
83
+ end
84
+
85
+ def as_current
86
+ old_object = self.class.current if self.class.current?
87
+ self.class.current = self
88
+ yield
89
+ ensure
90
+ self.class.current = old_object
91
+ end
92
+
93
+ def current?
94
+ self.class.current? && equal?(self.class.current)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'registry_dependent_on'
4
+
5
+ module RailsMultitenant
6
+ module GlobalContextRegistry
7
+ # This module allows you to have a current, thread-local instance
8
+ # of a class. This module assumes that you are mixing into a Rails
9
+ # model, and separately stores and id in thread local storage for
10
+ # lazy loading.
11
+ module CurrentInstance
12
+ extend ActiveSupport::Concern
13
+
14
+ module ClassMethods
15
+ def current_id=(id)
16
+ GlobalContextRegistry.delete(current_instance_registry_obj)
17
+ GlobalContextRegistry.set(current_instance_registry_id, id)
18
+ __clear_dependents!
19
+ end
20
+
21
+ def current=(object)
22
+ raise "#{object} is not a #{self}" if object.present? && !object.is_a?(self)
23
+
24
+ GlobalContextRegistry.set(current_instance_registry_obj, object)
25
+ GlobalContextRegistry.set(current_instance_registry_id, object.try(:id))
26
+ __clear_dependents!
27
+ end
28
+
29
+ def current_id
30
+ GlobalContextRegistry.get(current_instance_registry_id)
31
+ end
32
+
33
+ def current
34
+ GlobalContextRegistry.fetch(current_instance_registry_obj) do
35
+ (current_id ? find(current_id) : nil)
36
+ end
37
+ end
38
+
39
+ def current?
40
+ !!current
41
+ end
42
+
43
+ def current!
44
+ current || raise("No current #{name} set")
45
+ end
46
+
47
+ def as_current_id(id)
48
+ old_id = current_id
49
+ self.current_id = id
50
+ yield
51
+ ensure
52
+ self.current_id = old_id
53
+ end
54
+
55
+ def as_current(model)
56
+ old_model = current
57
+ self.current = model
58
+ yield
59
+ ensure
60
+ self.current = old_model
61
+ end
62
+
63
+ def clear_current!
64
+ GlobalContextRegistry.delete(current_instance_registry_obj)
65
+ end
66
+
67
+ private
68
+
69
+ def __clear_dependents!
70
+ key_class = respond_to?(:base_class) ? base_class : self
71
+ GlobalContextRegistry.send(:dependencies_for, key_class).each(&:clear_current!)
72
+ end
73
+
74
+ def current_instance_registry_id
75
+ return @current_instance_registry_id if @current_instance_registry_id
76
+
77
+ key_class = respond_to?(:base_class) ? base_class : self
78
+ @current_instance_registry_id = "#{key_class.name.underscore}_id".to_sym
79
+ end
80
+
81
+ def current_instance_registry_obj
82
+ return @current_instance_registry_obj if @current_instance_registry_obj
83
+
84
+ key_class = respond_to?(:base_class) ? base_class : self
85
+ @current_instance_registry_obj = "#{key_class.name.underscore}_obj".to_sym
86
+ end
87
+ include RegistryDependentOn
88
+ end
89
+
90
+ def as_current
91
+ old_id = self.class.current_id
92
+ self.class.current = self
93
+ yield
94
+ ensure
95
+ self.class.current_id = old_id
96
+ end
97
+
98
+ def current?
99
+ id == self.class.current_id
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMultitenant
4
+ module GlobalContextRegistry
5
+ module RegistryDependentOn
6
+ # Is this class dependent on changes in another GlobalContextRegistry-
7
+ # stored object? Register that dependency here.
8
+ def global_context_dependent_on(*klasses)
9
+ klasses.each { |klass| GlobalContextRegistry.send(:add_dependency, klass, self) }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'global_context_registry/current'
4
+ require_relative 'global_context_registry/current_instance'
5
+ require_relative 'global_context_registry/registry_dependent_on'
6
+
3
7
  # Handles storing of global state that may be swapped out or unset at
4
8
  # various points. We use this in dandelion to store the current user,
5
9
  # org, catalog, etc.
@@ -8,207 +12,8 @@
8
12
  #
9
13
  module RailsMultitenant
10
14
  module GlobalContextRegistry
11
-
12
15
  extend self
13
16
 
14
- module RegistryDependentOn
15
-
16
- # Is this class dependent on changes in another GlobalContextRegistry-
17
- # stored object? Register that dependency here.
18
- def global_context_dependent_on(*klasses)
19
- klasses.each { |klass| GlobalContextRegistry.send(:add_dependency, klass, self) }
20
- end
21
- end
22
-
23
- # This module allows your to have a current, thread-local instance
24
- # of this class. It currently assumes your class has a zero-arg
25
- # constructor.
26
- module Current
27
- extend ActiveSupport::Concern
28
-
29
- included do
30
- class_attribute :default_provider, instance_writer: false
31
- end
32
-
33
- module ClassMethods
34
- def current
35
- GlobalContextRegistry.fetch(current_registry_obj) { __current_default }
36
- end
37
-
38
- def current=(object)
39
- raise "#{object} is not a #{self}" if object.present? && !object.is_a?(self)
40
-
41
- GlobalContextRegistry.set(current_registry_obj, object)
42
- __clear_dependents!
43
- end
44
-
45
- def current?
46
- GlobalContextRegistry.get(current_registry_obj).present?
47
- end
48
-
49
- def current!
50
- current || raise("No current #{name} set")
51
- end
52
-
53
- def clear_current!
54
- GlobalContextRegistry.delete(current_registry_obj)
55
- end
56
-
57
- def as_current(object)
58
- old_object = current if current?
59
- self.current = object
60
- yield
61
- ensure
62
- self.current = old_object
63
- end
64
-
65
- include RegistryDependentOn
66
-
67
- def provide_default(provider = nil, &block)
68
- self.default_provider = provider ? provider.to_proc : block
69
- end
70
-
71
- private
72
-
73
- def current_registry_obj
74
- return @current_registry_obj if @current_registry_obj
75
-
76
- @current_registry_obj = "#{__key_class.name.underscore}_obj".to_sym
77
- end
78
-
79
- def current_registry_default_provider
80
- "#{__key_class.name.underscore}_default_provider".to_sym
81
- end
82
-
83
- def __current_default
84
- if default_provider
85
- default = default_provider.call(self)
86
- raise "#{default} is not a #{self}" if default.present? && !default.is_a?(self)
87
-
88
- default
89
- end
90
- end
91
-
92
- def __clear_dependents!
93
- GlobalContextRegistry.send(:dependencies_for, __key_class).each(&:clear_current!)
94
- end
95
-
96
- def __key_class
97
- respond_to?(:base_class) ? base_class : self
98
- end
99
- end
100
-
101
- def as_current
102
- old_object = self.class.current if self.class.current?
103
- self.class.current = self
104
- yield
105
- ensure
106
- self.class.current = old_object
107
- end
108
-
109
- def current?
110
- self.class.current? && equal?(self.class.current)
111
- end
112
-
113
- end
114
-
115
- # This module allows you to have a current, thread-local instance
116
- # of a class. This module assumes that you are mixing into a Rails
117
- # model, and separately stores and id in thread local storage for
118
- # lazy loading.
119
- module CurrentInstance
120
- extend ActiveSupport::Concern
121
-
122
- module ClassMethods
123
- def current_id=(id)
124
- GlobalContextRegistry.delete(current_instance_registry_obj)
125
- GlobalContextRegistry.set(current_instance_registry_id, id)
126
- __clear_dependents!
127
- end
128
-
129
- def current=(object)
130
- raise "#{object} is not a #{self}" if object.present? && !object.is_a?(self)
131
-
132
- GlobalContextRegistry.set(current_instance_registry_obj, object)
133
- GlobalContextRegistry.set(current_instance_registry_id, object.try(:id))
134
- __clear_dependents!
135
- end
136
-
137
- def current_id
138
- GlobalContextRegistry.get(current_instance_registry_id)
139
- end
140
-
141
- def current
142
- GlobalContextRegistry.fetch(current_instance_registry_obj) do
143
- (current_id ? find(current_id) : nil)
144
- end
145
- end
146
-
147
- def current?
148
- !!current
149
- end
150
-
151
- def current!
152
- current || raise("No current #{name} set")
153
- end
154
-
155
- def as_current_id(id)
156
- old_id = current_id
157
- self.current_id = id
158
- yield
159
- ensure
160
- self.current_id = old_id
161
- end
162
-
163
- def as_current(model)
164
- old_model = current
165
- self.current = model
166
- yield
167
- ensure
168
- self.current = old_model
169
- end
170
-
171
- def clear_current!
172
- GlobalContextRegistry.delete(current_instance_registry_obj)
173
- end
174
-
175
- private
176
-
177
- def __clear_dependents!
178
- key_class = respond_to?(:base_class) ? base_class : self
179
- GlobalContextRegistry.send(:dependencies_for, key_class).each(&:clear_current!)
180
- end
181
-
182
- def current_instance_registry_id
183
- return @current_instance_registry_id if @current_instance_registry_id
184
-
185
- key_class = respond_to?(:base_class) ? base_class : self
186
- @current_instance_registry_id = "#{key_class.name.underscore}_id".to_sym
187
- end
188
-
189
- def current_instance_registry_obj
190
- return @current_instance_registry_obj if @current_instance_registry_obj
191
-
192
- key_class = respond_to?(:base_class) ? base_class : self
193
- @current_instance_registry_obj = "#{key_class.name.underscore}_obj".to_sym
194
- end
195
- include RegistryDependentOn
196
- end
197
-
198
- def as_current
199
- old_id = self.class.current_id
200
- self.class.current = self
201
- yield
202
- ensure
203
- self.class.current_id = old_id
204
- end
205
-
206
- def current?
207
- id == self.class.current_id
208
- end
209
-
210
- end
211
-
212
17
  # Set this global
213
18
  def set(symbol, value)
214
19
  globals[symbol] = value
@@ -243,8 +48,8 @@ module RailsMultitenant
243
48
 
244
49
  # Duplicate the registry
245
50
  def duplicate_registry
246
- globals.each_with_object({}) do |(key, value), result|
247
- result[key] = value.nil? || value.is_a?(Integer) ? value : value.dup
51
+ globals.transform_values do |value|
52
+ value.nil? || value.is_a?(Integer) ? value : value.dup
248
53
  end
249
54
  end
250
55
 
@@ -280,6 +85,30 @@ module RailsMultitenant
280
85
  self.globals = registry
281
86
  end
282
87
 
88
+ # Run a block of code that disregards scoping during read queries
89
+ def with_unscoped_queries
90
+ # disabling Style/ExplicitBlockArgument for performance reasons
91
+ with_merged_registry(__use_unscoped_queries: true) do # rubocop:disable Style/ExplicitBlockArgument
92
+ yield
93
+ end
94
+ end
95
+
96
+ def use_unscoped_queries?
97
+ self[:__use_unscoped_queries] == true
98
+ end
99
+
100
+ # Prefer .with_unscoped_queries to the following two methods.
101
+ # Note: these methods are intended for use in a manner like .with_admin_registry,
102
+ # but in contexts where around semantics are not allowed.
103
+
104
+ def disable_scoped_queries
105
+ self[:__use_unscoped_queries] = true
106
+ end
107
+
108
+ def enable_scoped_queries
109
+ self[:__use_unscoped_queries] = nil
110
+ end
111
+
283
112
  private
284
113
 
285
114
  @dependencies = {}
@@ -18,7 +18,9 @@ module RailsMultitenant
18
18
  scope_sym = "from_current_#{context_entity}".to_sym
19
19
 
20
20
  scope scope_sym, -> do
21
- where(context_entity_id_field => GlobalContextRegistry[context_entity_id_field])
21
+ unless GlobalContextRegistry.use_unscoped_queries?
22
+ where(context_entity_id_field => GlobalContextRegistry[context_entity_id_field])
23
+ end
22
24
  end
23
25
 
24
26
  default_scope { send(scope_sym) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsMultitenant
4
- VERSION = '0.13.0'
4
+ VERSION = '0.16.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_multitenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Breault
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-01 00:00:00.000000000 Z
11
+ date: 2022-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,40 +16,40 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '5.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.1'
22
+ version: '7.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '4.2'
29
+ version: '5.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.1'
32
+ version: '7.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activesupport
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '4.2'
39
+ version: '5.2'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '6.1'
42
+ version: '7.1'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: '4.2'
49
+ version: '5.2'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '6.1'
52
+ version: '7.1'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: appraisal
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -120,20 +120,34 @@ dependencies:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
122
  version: 3.8.0
123
+ - !ruby/object:Gem::Dependency
124
+ name: rspec_junit_formatter
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
123
137
  - !ruby/object:Gem::Dependency
124
138
  name: salsify_rubocop
125
139
  requirement: !ruby/object:Gem::Requirement
126
140
  requirements:
127
- - - '='
141
+ - - "~>"
128
142
  - !ruby/object:Gem::Version
129
- version: 0.63.0
143
+ version: 1.0.1
130
144
  type: :development
131
145
  prerelease: false
132
146
  version_requirements: !ruby/object:Gem::Requirement
133
147
  requirements:
134
- - - '='
148
+ - - "~>"
135
149
  - !ruby/object:Gem::Version
136
- version: 0.63.0
150
+ version: 1.0.1
137
151
  - !ruby/object:Gem::Dependency
138
152
  name: simplecov
139
153
  requirement: !ruby/object:Gem::Requirement
@@ -172,6 +186,9 @@ files:
172
186
  - LICENSE.txt
173
187
  - lib/rails_multitenant.rb
174
188
  - lib/rails_multitenant/global_context_registry.rb
189
+ - lib/rails_multitenant/global_context_registry/current.rb
190
+ - lib/rails_multitenant/global_context_registry/current_instance.rb
191
+ - lib/rails_multitenant/global_context_registry/registry_dependent_on.rb
175
192
  - lib/rails_multitenant/middleware/extensions.rb
176
193
  - lib/rails_multitenant/middleware/isolated_context_registry.rb
177
194
  - lib/rails_multitenant/middleware/railtie.rb
@@ -181,7 +198,9 @@ files:
181
198
  homepage: https://github.com/salsify/rails-multitenant
182
199
  licenses:
183
200
  - MIT
184
- metadata: {}
201
+ metadata:
202
+ allowed_push_host: https://rubygems.org
203
+ rubygems_mfa_required: 'true'
185
204
  post_install_message:
186
205
  rdoc_options: []
187
206
  require_paths:
@@ -190,14 +209,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
209
  requirements:
191
210
  - - ">="
192
211
  - !ruby/object:Gem::Version
193
- version: 2.4.0
212
+ version: 2.7.0
194
213
  required_rubygems_version: !ruby/object:Gem::Requirement
195
214
  requirements:
196
215
  - - ">="
197
216
  - !ruby/object:Gem::Version
198
217
  version: '0'
199
218
  requirements: []
200
- rubygems_version: 3.0.4
219
+ rubygems_version: 3.2.22
201
220
  signing_key:
202
221
  specification_version: 4
203
222
  summary: Automatically configures multiple tenants in a Rails environment