activerecord-multi-tenant 1.0.0 → 1.1.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 +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +6 -14
- data/Appraisals +24 -24
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +79 -63
- data/README.md +1 -1
- data/activerecord-multi-tenant.gemspec +1 -1
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/active_record_5.2.gemfile +10 -2
- data/gemfiles/active_record_5.2.gemfile.lock +102 -96
- data/gemfiles/{active_record_5.1.gemfile → active_record_6.0.gemfile} +2 -2
- data/gemfiles/active_record_6.0.gemfile.lock +198 -0
- data/gemfiles/rails_5.2.gemfile +10 -2
- data/gemfiles/rails_5.2.gemfile.lock +109 -103
- data/gemfiles/{rails_5.0.gemfile → rails_6.0.gemfile} +2 -2
- data/gemfiles/rails_6.0.gemfile.lock +198 -0
- data/lib/activerecord-multi-tenant.rb +1 -0
- data/lib/activerecord-multi-tenant/controller_extensions.rb +2 -6
- data/lib/activerecord-multi-tenant/copy_from_client.rb +2 -2
- data/lib/activerecord-multi-tenant/migrations.rb +2 -2
- data/lib/activerecord-multi-tenant/model_extensions.rb +8 -15
- data/lib/activerecord-multi-tenant/multi_tenant.rb +9 -0
- data/lib/activerecord-multi-tenant/persistence_extension.rb +13 -0
- data/lib/activerecord-multi-tenant/query_rewriter.rb +59 -105
- data/lib/activerecord-multi-tenant/sidekiq.rb +2 -1
- data/lib/activerecord-multi-tenant/version.rb +1 -1
- data/spec/activerecord-multi-tenant/controller_extensions_spec.rb +19 -24
- data/spec/activerecord-multi-tenant/model_extensions_spec.rb +54 -104
- data/spec/activerecord-multi-tenant/query_rewriter_spec.rb +40 -0
- data/spec/activerecord-multi-tenant/record_modifications_spec.rb +60 -3
- data/spec/activerecord-multi-tenant/schema_dumper_tester.rb +0 -0
- data/spec/activerecord-multi-tenant/sidekiq_spec.rb +4 -4
- data/spec/schema.rb +1 -4
- data/spec/spec_helper.rb +1 -6
- metadata +15 -20
- data/gemfiles/active_record_5.1.gemfile.lock +0 -173
- data/gemfiles/rails_4.0.gemfile +0 -8
- data/gemfiles/rails_4.0.gemfile.lock +0 -141
- data/gemfiles/rails_4.1.gemfile +0 -8
- data/gemfiles/rails_4.1.gemfile.lock +0 -146
- data/gemfiles/rails_4.2.gemfile +0 -8
- data/gemfiles/rails_4.2.gemfile.lock +0 -169
- data/gemfiles/rails_5.0.gemfile.lock +0 -175
- data/gemfiles/rails_5.1.gemfile +0 -8
- data/gemfiles/rails_5.1.gemfile.lock +0 -175
@@ -0,0 +1,198 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
activerecord-multi-tenant (1.1.0)
|
5
|
+
rails (>= 4.2)
|
6
|
+
request_store (>= 1.0.5)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actioncable (6.0.3.1)
|
12
|
+
actionpack (= 6.0.3.1)
|
13
|
+
nio4r (~> 2.0)
|
14
|
+
websocket-driver (>= 0.6.1)
|
15
|
+
actionmailbox (6.0.3.1)
|
16
|
+
actionpack (= 6.0.3.1)
|
17
|
+
activejob (= 6.0.3.1)
|
18
|
+
activerecord (= 6.0.3.1)
|
19
|
+
activestorage (= 6.0.3.1)
|
20
|
+
activesupport (= 6.0.3.1)
|
21
|
+
mail (>= 2.7.1)
|
22
|
+
actionmailer (6.0.3.1)
|
23
|
+
actionpack (= 6.0.3.1)
|
24
|
+
actionview (= 6.0.3.1)
|
25
|
+
activejob (= 6.0.3.1)
|
26
|
+
mail (~> 2.5, >= 2.5.4)
|
27
|
+
rails-dom-testing (~> 2.0)
|
28
|
+
actionpack (6.0.3.1)
|
29
|
+
actionview (= 6.0.3.1)
|
30
|
+
activesupport (= 6.0.3.1)
|
31
|
+
rack (~> 2.0, >= 2.0.8)
|
32
|
+
rack-test (>= 0.6.3)
|
33
|
+
rails-dom-testing (~> 2.0)
|
34
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
35
|
+
actiontext (6.0.3.1)
|
36
|
+
actionpack (= 6.0.3.1)
|
37
|
+
activerecord (= 6.0.3.1)
|
38
|
+
activestorage (= 6.0.3.1)
|
39
|
+
activesupport (= 6.0.3.1)
|
40
|
+
nokogiri (>= 1.8.5)
|
41
|
+
actionview (6.0.3.1)
|
42
|
+
activesupport (= 6.0.3.1)
|
43
|
+
builder (~> 3.1)
|
44
|
+
erubi (~> 1.4)
|
45
|
+
rails-dom-testing (~> 2.0)
|
46
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
47
|
+
activejob (6.0.3.1)
|
48
|
+
activesupport (= 6.0.3.1)
|
49
|
+
globalid (>= 0.3.6)
|
50
|
+
activemodel (6.0.3.1)
|
51
|
+
activesupport (= 6.0.3.1)
|
52
|
+
activerecord (6.0.3.1)
|
53
|
+
activemodel (= 6.0.3.1)
|
54
|
+
activesupport (= 6.0.3.1)
|
55
|
+
activestorage (6.0.3.1)
|
56
|
+
actionpack (= 6.0.3.1)
|
57
|
+
activejob (= 6.0.3.1)
|
58
|
+
activerecord (= 6.0.3.1)
|
59
|
+
marcel (~> 0.3.1)
|
60
|
+
activesupport (6.0.3.1)
|
61
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
62
|
+
i18n (>= 0.7, < 2)
|
63
|
+
minitest (~> 5.1)
|
64
|
+
tzinfo (~> 1.1)
|
65
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
66
|
+
appraisal (2.2.0)
|
67
|
+
bundler
|
68
|
+
rake
|
69
|
+
thor (>= 0.14.0)
|
70
|
+
builder (3.2.4)
|
71
|
+
byebug (11.1.3)
|
72
|
+
coderay (1.1.2)
|
73
|
+
concurrent-ruby (1.1.6)
|
74
|
+
connection_pool (2.2.2)
|
75
|
+
crass (1.0.6)
|
76
|
+
diff-lcs (1.3)
|
77
|
+
erubi (1.9.0)
|
78
|
+
globalid (0.4.2)
|
79
|
+
activesupport (>= 4.2.0)
|
80
|
+
i18n (1.8.2)
|
81
|
+
concurrent-ruby (~> 1.0)
|
82
|
+
loofah (2.5.0)
|
83
|
+
crass (~> 1.0.2)
|
84
|
+
nokogiri (>= 1.5.9)
|
85
|
+
mail (2.7.1)
|
86
|
+
mini_mime (>= 0.1.1)
|
87
|
+
marcel (0.3.3)
|
88
|
+
mimemagic (~> 0.3.2)
|
89
|
+
method_source (1.0.0)
|
90
|
+
mimemagic (0.3.5)
|
91
|
+
mini_mime (1.0.2)
|
92
|
+
mini_portile2 (2.4.0)
|
93
|
+
minitest (5.14.1)
|
94
|
+
nio4r (2.5.2)
|
95
|
+
nokogiri (1.10.9)
|
96
|
+
mini_portile2 (~> 2.4.0)
|
97
|
+
pg (1.2.3)
|
98
|
+
pry (0.13.1)
|
99
|
+
coderay (~> 1.1)
|
100
|
+
method_source (~> 1.0)
|
101
|
+
pry-byebug (3.9.0)
|
102
|
+
byebug (~> 11.0)
|
103
|
+
pry (~> 0.13.0)
|
104
|
+
rack (2.2.2)
|
105
|
+
rack-protection (2.0.8.1)
|
106
|
+
rack
|
107
|
+
rack-test (1.1.0)
|
108
|
+
rack (>= 1.0, < 3)
|
109
|
+
rails (6.0.3.1)
|
110
|
+
actioncable (= 6.0.3.1)
|
111
|
+
actionmailbox (= 6.0.3.1)
|
112
|
+
actionmailer (= 6.0.3.1)
|
113
|
+
actionpack (= 6.0.3.1)
|
114
|
+
actiontext (= 6.0.3.1)
|
115
|
+
actionview (= 6.0.3.1)
|
116
|
+
activejob (= 6.0.3.1)
|
117
|
+
activemodel (= 6.0.3.1)
|
118
|
+
activerecord (= 6.0.3.1)
|
119
|
+
activestorage (= 6.0.3.1)
|
120
|
+
activesupport (= 6.0.3.1)
|
121
|
+
bundler (>= 1.3.0)
|
122
|
+
railties (= 6.0.3.1)
|
123
|
+
sprockets-rails (>= 2.0.0)
|
124
|
+
rails-dom-testing (2.0.3)
|
125
|
+
activesupport (>= 4.2.0)
|
126
|
+
nokogiri (>= 1.6)
|
127
|
+
rails-html-sanitizer (1.3.0)
|
128
|
+
loofah (~> 2.3)
|
129
|
+
railties (6.0.3.1)
|
130
|
+
actionpack (= 6.0.3.1)
|
131
|
+
activesupport (= 6.0.3.1)
|
132
|
+
method_source
|
133
|
+
rake (>= 0.8.7)
|
134
|
+
thor (>= 0.20.3, < 2.0)
|
135
|
+
rake (13.0.1)
|
136
|
+
redis (4.1.4)
|
137
|
+
request_store (1.5.0)
|
138
|
+
rack (>= 1.4)
|
139
|
+
rspec (3.9.0)
|
140
|
+
rspec-core (~> 3.9.0)
|
141
|
+
rspec-expectations (~> 3.9.0)
|
142
|
+
rspec-mocks (~> 3.9.0)
|
143
|
+
rspec-core (3.9.2)
|
144
|
+
rspec-support (~> 3.9.3)
|
145
|
+
rspec-expectations (3.9.2)
|
146
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
147
|
+
rspec-support (~> 3.9.0)
|
148
|
+
rspec-mocks (3.9.1)
|
149
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
150
|
+
rspec-support (~> 3.9.0)
|
151
|
+
rspec-rails (4.0.1)
|
152
|
+
actionpack (>= 4.2)
|
153
|
+
activesupport (>= 4.2)
|
154
|
+
railties (>= 4.2)
|
155
|
+
rspec-core (~> 3.9)
|
156
|
+
rspec-expectations (~> 3.9)
|
157
|
+
rspec-mocks (~> 3.9)
|
158
|
+
rspec-support (~> 3.9)
|
159
|
+
rspec-support (3.9.3)
|
160
|
+
sidekiq (6.0.7)
|
161
|
+
connection_pool (>= 2.2.2)
|
162
|
+
rack (~> 2.0)
|
163
|
+
rack-protection (>= 2.0.0)
|
164
|
+
redis (>= 4.1.0)
|
165
|
+
sprockets (4.0.0)
|
166
|
+
concurrent-ruby (~> 1.0)
|
167
|
+
rack (> 1, < 3)
|
168
|
+
sprockets-rails (3.2.1)
|
169
|
+
actionpack (>= 4.0)
|
170
|
+
activesupport (>= 4.0)
|
171
|
+
sprockets (>= 3.0.0)
|
172
|
+
thor (1.0.1)
|
173
|
+
thread_safe (0.3.6)
|
174
|
+
tzinfo (1.2.7)
|
175
|
+
thread_safe (~> 0.1)
|
176
|
+
websocket-driver (0.7.2)
|
177
|
+
websocket-extensions (>= 0.1.0)
|
178
|
+
websocket-extensions (0.1.4)
|
179
|
+
zeitwerk (2.3.0)
|
180
|
+
|
181
|
+
PLATFORMS
|
182
|
+
ruby
|
183
|
+
|
184
|
+
DEPENDENCIES
|
185
|
+
activerecord-multi-tenant!
|
186
|
+
appraisal
|
187
|
+
pg
|
188
|
+
pry
|
189
|
+
pry-byebug
|
190
|
+
rails (~> 6.0.3)
|
191
|
+
rake
|
192
|
+
rspec (>= 3.0)
|
193
|
+
rspec-rails
|
194
|
+
sidekiq
|
195
|
+
thor
|
196
|
+
|
197
|
+
BUNDLED WITH
|
198
|
+
2.1.4
|
@@ -10,3 +10,4 @@ require_relative 'activerecord-multi-tenant/query_rewriter'
|
|
10
10
|
require_relative 'activerecord-multi-tenant/query_monitor'
|
11
11
|
require_relative 'activerecord-multi-tenant/version'
|
12
12
|
require_relative 'activerecord-multi-tenant/with_lock'
|
13
|
+
require_relative 'activerecord-multi-tenant/persistence_extension'
|
@@ -20,10 +20,6 @@ module MultiTenant
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
if defined?(ActionController::API)
|
28
|
-
ActionController::API.extend MultiTenant::ControllerExtensions
|
23
|
+
ActiveSupport.on_load(:action_controller) do |base|
|
24
|
+
base.extend MultiTenant::ControllerExtensions
|
29
25
|
end
|
@@ -44,10 +44,10 @@ module ActiveRecord
|
|
44
44
|
module SchemaStatements
|
45
45
|
alias :orig_create_table :create_table
|
46
46
|
def create_table(table_name, options = {}, &block)
|
47
|
-
ret = orig_create_table(table_name, options.except(:partition_key), &block)
|
47
|
+
ret = orig_create_table(table_name, **options.except(:partition_key), &block)
|
48
48
|
if options[:partition_key] && options[:partition_key].to_s != 'id'
|
49
49
|
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{table_name}_pkey"
|
50
|
-
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(
|
50
|
+
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(\"#{options[:partition_key]}\", id)"
|
51
51
|
end
|
52
52
|
ret
|
53
53
|
end
|
@@ -24,11 +24,6 @@ module MultiTenant
|
|
24
24
|
def primary_key
|
25
25
|
return @primary_key if @primary_key
|
26
26
|
|
27
|
-
if ::ActiveRecord::VERSION::MAJOR < 5
|
28
|
-
@primary_key = super || DEFAULT_ID_FIELD
|
29
|
-
return @primary_key if connection.schema_cache.columns_hash(table_name).include? @primary_key
|
30
|
-
end
|
31
|
-
|
32
27
|
primary_object_keys = Array.wrap(connection.schema_cache.primary_keys(table_name)) - [partition_key]
|
33
28
|
|
34
29
|
if primary_object_keys.size == 1
|
@@ -54,7 +49,7 @@ module MultiTenant
|
|
54
49
|
|
55
50
|
# Create an implicit belongs_to association only if tenant class exists
|
56
51
|
if MultiTenant.tenant_klass_defined?(tenant_name)
|
57
|
-
belongs_to tenant_name, options.slice(:class_name, :inverse_of).merge(foreign_key: options[:partition_key])
|
52
|
+
belongs_to tenant_name, **options.slice(:class_name, :inverse_of).merge(foreign_key: options[:partition_key])
|
58
53
|
end
|
59
54
|
|
60
55
|
# New instances should have the tenant set
|
@@ -126,16 +121,14 @@ module MultiTenant
|
|
126
121
|
end
|
127
122
|
end
|
128
123
|
|
129
|
-
|
130
|
-
|
124
|
+
ActiveSupport.on_load(:active_record) do |base|
|
125
|
+
base.extend MultiTenant::ModelExtensionsClassMethods
|
131
126
|
end
|
132
127
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
skip_statement_cache_orig(*scope)
|
139
|
-
end
|
128
|
+
class ActiveRecord::Associations::Association
|
129
|
+
alias skip_statement_cache_orig skip_statement_cache?
|
130
|
+
def skip_statement_cache?(*scope)
|
131
|
+
return true if klass.respond_to?(:scoped_by_tenant?) && klass.scoped_by_tenant?
|
132
|
+
skip_statement_cache_orig(*scope)
|
140
133
|
end
|
141
134
|
end
|
@@ -33,6 +33,15 @@ module MultiTenant
|
|
33
33
|
@@multi_tenant_models[table_name.to_s]
|
34
34
|
end
|
35
35
|
|
36
|
+
def self.multi_tenant_model_for_arel(arel)
|
37
|
+
return nil unless arel.respond_to?(:ast)
|
38
|
+
if arel.ast.relation.is_a? Arel::Nodes::JoinSource
|
39
|
+
MultiTenant.multi_tenant_model_for_table(arel.ast.relation.left.table_name)
|
40
|
+
else
|
41
|
+
MultiTenant.multi_tenant_model_for_table(arel.ast.relation.table_name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
36
45
|
def self.current_tenant=(tenant)
|
37
46
|
RequestStore.store[:current_tenant] = tenant
|
38
47
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Persistence
|
3
|
+
alias :delete_orig :delete
|
4
|
+
|
5
|
+
def delete
|
6
|
+
if MultiTenant.multi_tenant_model_for_table(self.class.table_name).present? && persisted? && MultiTenant.current_tenant_id.nil?
|
7
|
+
MultiTenant.with(self.public_send(self.class.partition_key)) { delete_orig }
|
8
|
+
else
|
9
|
+
delete_orig
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -149,21 +149,27 @@ module MultiTenant
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
-
class
|
152
|
+
class BaseTenantEnforcementClause < Arel::Nodes::Node
|
153
153
|
attr_reader :tenant_attribute
|
154
154
|
def initialize(tenant_attribute)
|
155
155
|
@tenant_attribute = tenant_attribute
|
156
|
+
@tenant_model = MultiTenant.multi_tenant_model_for_table(tenant_attribute.relation.table_name)
|
156
157
|
end
|
157
158
|
|
158
159
|
def to_s; to_sql; end
|
159
160
|
def to_str; to_sql; end
|
160
161
|
|
161
162
|
def to_sql(*)
|
162
|
-
|
163
|
+
collector = Arel::Collectors::SQLString.new
|
164
|
+
collector = @tenant_model.connection.visitor.accept tenant_arel, collector
|
165
|
+
collector.value
|
163
166
|
end
|
164
167
|
|
165
|
-
private
|
166
168
|
|
169
|
+
end
|
170
|
+
|
171
|
+
class TenantEnforcementClause < BaseTenantEnforcementClause
|
172
|
+
private
|
167
173
|
def tenant_arel
|
168
174
|
if defined?(Arel::Nodes::Quoted)
|
169
175
|
@tenant_attribute.eq(Arel::Nodes::Quoted.new(MultiTenant.current_tenant_id))
|
@@ -174,24 +180,15 @@ module MultiTenant
|
|
174
180
|
end
|
175
181
|
|
176
182
|
|
177
|
-
class TenantJoinEnforcementClause <
|
178
|
-
attr_reader :tenant_attribute
|
183
|
+
class TenantJoinEnforcementClause < BaseTenantEnforcementClause
|
179
184
|
attr_reader :table_left
|
180
185
|
def initialize(tenant_attribute, table_left)
|
186
|
+
super(tenant_attribute)
|
181
187
|
@table_left = table_left
|
182
188
|
@model_left = MultiTenant.multi_tenant_model_for_table(table_left.table_name)
|
183
|
-
@tenant_attribute = tenant_attribute
|
184
|
-
end
|
185
|
-
|
186
|
-
def to_s; to_sql; end
|
187
|
-
def to_str; to_sql; end
|
188
|
-
|
189
|
-
def to_sql(*)
|
190
|
-
tenant_arel.to_sql
|
191
189
|
end
|
192
190
|
|
193
191
|
private
|
194
|
-
|
195
192
|
def tenant_arel
|
196
193
|
@tenant_attribute.eq(@table_left[@model_left.partition_key])
|
197
194
|
end
|
@@ -199,23 +196,12 @@ module MultiTenant
|
|
199
196
|
|
200
197
|
|
201
198
|
module TenantValueVisitor
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
end
|
206
|
-
|
207
|
-
def visit_MultiTenant_TenantJoinEnforcementClause(o, collector)
|
208
|
-
collector << o
|
209
|
-
end
|
210
|
-
|
211
|
-
else
|
212
|
-
def visit_MultiTenant_TenantEnforcementClause(o, a = nil)
|
213
|
-
o
|
214
|
-
end
|
199
|
+
def visit_MultiTenant_TenantEnforcementClause(o, collector)
|
200
|
+
collector << o
|
201
|
+
end
|
215
202
|
|
216
|
-
|
217
|
-
|
218
|
-
end
|
203
|
+
def visit_MultiTenant_TenantJoinEnforcementClause(o, collector)
|
204
|
+
collector << o
|
219
205
|
end
|
220
206
|
end
|
221
207
|
|
@@ -223,7 +209,7 @@ module MultiTenant
|
|
223
209
|
def join_to_update(update, *args)
|
224
210
|
update = super(update, *args)
|
225
211
|
model = MultiTenant.multi_tenant_model_for_table(update.ast.relation.table_name)
|
226
|
-
if model.present? && !MultiTenant.with_write_only_mode_enabled?
|
212
|
+
if model.present? && !MultiTenant.with_write_only_mode_enabled? && MultiTenant.current_tenant_id.present?
|
227
213
|
update.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
|
228
214
|
end
|
229
215
|
update
|
@@ -232,28 +218,26 @@ module MultiTenant
|
|
232
218
|
def join_to_delete(delete, *args)
|
233
219
|
delete = super(delete, *args)
|
234
220
|
model = MultiTenant.multi_tenant_model_for_table(delete.ast.left.table_name)
|
235
|
-
if model.present? && !MultiTenant.with_write_only_mode_enabled?
|
221
|
+
if model.present? && !MultiTenant.with_write_only_mode_enabled? && MultiTenant.current_tenant_id.present?
|
236
222
|
delete.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
|
237
223
|
end
|
238
224
|
delete
|
239
225
|
end
|
240
226
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
arel.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
|
246
|
-
end
|
247
|
-
super(arel, name, binds)
|
227
|
+
def update(arel, name = nil, binds = [])
|
228
|
+
model = MultiTenant.multi_tenant_model_for_arel(arel)
|
229
|
+
if model.present? && !MultiTenant.with_write_only_mode_enabled? && MultiTenant.current_tenant_id.present?
|
230
|
+
arel.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
|
248
231
|
end
|
232
|
+
super(arel, name, binds)
|
233
|
+
end
|
249
234
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
end
|
255
|
-
super(arel, name, binds)
|
235
|
+
def delete(arel, name = nil, binds = [])
|
236
|
+
model = MultiTenant.multi_tenant_model_for_arel(arel)
|
237
|
+
if model.present? && !MultiTenant.with_write_only_mode_enabled? && MultiTenant.current_tenant_id.present?
|
238
|
+
arel.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
|
256
239
|
end
|
240
|
+
super(arel, name, binds)
|
257
241
|
end
|
258
242
|
end
|
259
243
|
end
|
@@ -296,7 +280,6 @@ module ActiveRecord
|
|
296
280
|
end
|
297
281
|
|
298
282
|
if node.is_a?(Arel::Nodes::SelectCore) || node.is_a?(Arel::Nodes::Join)
|
299
|
-
|
300
283
|
if node.is_a?Arel::Nodes::Join
|
301
284
|
node_list = [node]
|
302
285
|
else
|
@@ -304,14 +287,18 @@ module ActiveRecord
|
|
304
287
|
end
|
305
288
|
|
306
289
|
node_list.select{ |n| n.is_a? Arel::Nodes::Join }.each do |node_join|
|
307
|
-
if !node_join.right ||
|
290
|
+
if (!node_join.right ||
|
291
|
+
(ActiveRecord::VERSION::MAJOR == 5 &&
|
292
|
+
!node_join.right.expr.right.is_a?(Arel::Attributes::Attribute)))
|
308
293
|
next
|
309
294
|
end
|
310
295
|
|
311
|
-
relation_right = node_join
|
312
|
-
|
313
|
-
|
296
|
+
relation_right, relation_left = relations_from_node_join(node_join)
|
297
|
+
|
298
|
+
next unless relation_right && relation_left
|
299
|
+
|
314
300
|
model_right = MultiTenant.multi_tenant_model_for_table(relation_left.table_name)
|
301
|
+
model_left = MultiTenant.multi_tenant_model_for_table(relation_right.table_name)
|
315
302
|
if model_right && model_left
|
316
303
|
join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(relation_left[model_left.partition_key], relation_right)
|
317
304
|
node_join.right.expr = node_join.right.expr.and(join_enforcement_clause)
|
@@ -324,69 +311,36 @@ module ActiveRecord
|
|
324
311
|
|
325
312
|
arel
|
326
313
|
end
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
require 'active_record/base'
|
331
|
-
module MultiTenantFindBy
|
332
|
-
if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 2
|
333
|
-
# Disable caching for find and find_by in Rails 4.2 - we don't have a good
|
334
|
-
# way to prevent caching problems here when prepared statements are enabled
|
335
|
-
def find_by(*args)
|
336
|
-
return super unless respond_to?(:scoped_by_tenant?) && scoped_by_tenant?
|
337
|
-
|
338
|
-
# This duplicates a bunch of code from AR's find() method
|
339
|
-
return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
340
|
-
return super if default_scopes.any?
|
341
314
|
|
342
|
-
|
315
|
+
private
|
316
|
+
def relations_from_node_join(node_join)
|
317
|
+
if ActiveRecord::VERSION::MAJOR == 5 || node_join.right.expr.is_a?(Arel::Nodes::Equality)
|
318
|
+
return node_join.right.expr.right.relation, node_join.right.expr.left.relation
|
319
|
+
end
|
343
320
|
|
344
|
-
|
345
|
-
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
321
|
+
children = node_join.right.expr.children
|
346
322
|
|
347
|
-
|
323
|
+
tenant_applied = children.any?(MultiTenant::TenantEnforcementClause) || children.any?(MultiTenant::TenantJoinEnforcementClause)
|
324
|
+
if tenant_applied || children.empty?
|
325
|
+
return nil, nil
|
326
|
+
end
|
348
327
|
|
349
|
-
|
350
|
-
|
328
|
+
if children[0].right.respond_to?('relation') && children[0].left.respond_to?('relation')
|
329
|
+
return children[0].right.relation, children[0].left.relation
|
330
|
+
end
|
351
331
|
|
352
|
-
|
332
|
+
return nil, nil
|
353
333
|
end
|
334
|
+
end
|
335
|
+
end
|
354
336
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
return super unless ids.length == 1
|
360
|
-
return super if ids.first.kind_of?(Symbol)
|
361
|
-
return super if block_given? ||
|
362
|
-
primary_key.nil? ||
|
363
|
-
default_scopes.any? ||
|
364
|
-
current_scope ||
|
365
|
-
columns_hash.include?(inheritance_column) ||
|
366
|
-
ids.first.kind_of?(Array)
|
367
|
-
|
368
|
-
id = ids.first
|
369
|
-
if ActiveRecord::Base === id
|
370
|
-
id = id.id
|
371
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
372
|
-
You are passing an instance of ActiveRecord::Base to `find`.
|
373
|
-
Please pass the id of the object by calling `.id`
|
374
|
-
MSG
|
375
|
-
end
|
376
|
-
key = primary_key
|
377
|
-
|
378
|
-
# Ensure we never use the cached version
|
379
|
-
find_by_statement_cache.synchronize { find_by_statement_cache[key] = nil }
|
380
|
-
|
381
|
-
super
|
382
|
-
end
|
383
|
-
elsif ActiveRecord::VERSION::MAJOR > 4
|
384
|
-
def cached_find_by_statement(key, &block)
|
385
|
-
return super unless respond_to?(:scoped_by_tenant?) && scoped_by_tenant?
|
337
|
+
require 'active_record/base'
|
338
|
+
module MultiTenantFindBy
|
339
|
+
def cached_find_by_statement(key, &block)
|
340
|
+
return super unless respond_to?(:scoped_by_tenant?) && scoped_by_tenant?
|
386
341
|
|
387
|
-
|
388
|
-
|
389
|
-
end
|
342
|
+
key = Array.wrap(key) + [MultiTenant.current_tenant_id.to_s]
|
343
|
+
super(key, &block)
|
390
344
|
end
|
391
345
|
end
|
392
346
|
|