rails_multitenant 0.13.0 → 0.14.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: 7cee7c42f683984c490e56705e9de15107c6cdca9458abae424e733907450d1e
4
+ data.tar.gz: 0be7d4f76a8ba047e66b4316d601f507c4c2c0b97bad4015dff06e8368280bc1
5
5
  SHA512:
6
- metadata.gz: 8375cb4f2c2a0676f1cc8b049ee4b416025840f085bc270f3ace7ecb2d4cf2b32f7715418d0888ce71ed63667ecc33bd722502a04dc3683d71663ece746a53c3
7
- data.tar.gz: 450cb63b8d3b13c8e4fe4d4f2800933ec276faece554d3b5021eda1508f2d8a085282c7fa1e700e6b6aca666dc960a04721fe850d2bd68ee533b7d8420ee175d
6
+ metadata.gz: cb2fb69f85325ddc3a05af7a26a244e1a40fe2c7eb5082711bd3c33f3ff27339fb911d80f5b689dcc86f5d3842bc450aa31c78901afb3926041ce5711d594ccc
7
+ data.tar.gz: 4bb540fec11d2f8eaa77468bd7b35cf3d823ce35f4c057757c136b581dd0935455ad62b2245cf3425806f4ea176d04c5adb9c3b2acbcdcf5381c3ebf3d52df8a
@@ -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
@@ -280,6 +85,29 @@ 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
+ with_merged_registry(__use_unscoped_queries: true) do
91
+ yield
92
+ end
93
+ end
94
+
95
+ def use_unscoped_queries?
96
+ self[:__use_unscoped_queries] == true
97
+ end
98
+
99
+ # Prefer .with_unscoped_queries to the following two methods.
100
+ # Note: these methods are intended for use in a manner like .with_admin_registry,
101
+ # but in contexts where around semantics are not allowed.
102
+
103
+ def disable_scoped_queries
104
+ self[:__use_unscoped_queries] = true
105
+ end
106
+
107
+ def enable_scoped_queries
108
+ self[:__use_unscoped_queries] = nil
109
+ end
110
+
283
111
  private
284
112
 
285
113
  @dependencies = {}
@@ -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
@@ -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.14.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.14.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: 2020-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -172,6 +172,9 @@ files:
172
172
  - LICENSE.txt
173
173
  - lib/rails_multitenant.rb
174
174
  - lib/rails_multitenant/global_context_registry.rb
175
+ - lib/rails_multitenant/global_context_registry/current.rb
176
+ - lib/rails_multitenant/global_context_registry/current_instance.rb
177
+ - lib/rails_multitenant/global_context_registry/registry_dependent_on.rb
175
178
  - lib/rails_multitenant/middleware/extensions.rb
176
179
  - lib/rails_multitenant/middleware/isolated_context_registry.rb
177
180
  - lib/rails_multitenant/middleware/railtie.rb