rails_multitenant 0.13.0 → 0.14.0

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
  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