activerecord-multi-tenant 2.0.0 → 2.2.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/.github/workflows/CI.yml +0 -26
- data/Appraisals +0 -24
- data/CHANGELOG.md +29 -0
- data/README.md +1 -1
- data/activerecord-multi-tenant.gemspec +1 -1
- data/lib/activerecord-multi-tenant/migrations.rb +76 -9
- data/lib/activerecord-multi-tenant/model_extensions.rb +21 -4
- data/lib/activerecord-multi-tenant/multi_tenant.rb +35 -0
- data/lib/activerecord-multi-tenant/query_rewriter.rb +4 -3
- data/lib/activerecord-multi-tenant/sidekiq.rb +16 -0
- data/lib/activerecord-multi-tenant/version.rb +1 -1
- data/lib/activerecord-multi-tenant.rb +0 -1
- data/spec/activerecord-multi-tenant/associations_spec.rb +21 -0
- data/spec/activerecord-multi-tenant/model_extensions_spec.rb +83 -10
- data/spec/activerecord-multi-tenant/record_modifications_spec.rb +19 -0
- data/spec/schema.rb +0 -1
- metadata +5 -9
- data/gemfiles/active_record_5.2.3.gemfile +0 -16
- data/gemfiles/active_record_5.2.gemfile +0 -16
- data/gemfiles/rails_5.2.3.gemfile +0 -16
- data/gemfiles/rails_5.2.gemfile +0 -16
- data/lib/activerecord-multi-tenant/persistence_extension.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15ad19bf20781129dc1bd57d4e4b8eb8731044cea3b89f29a62789d0f5a45aee
|
|
4
|
+
data.tar.gz: 0f76290b00a7d540495972ab5a9de09d3abbb1dde11758d58b08493bf743b5da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17f7b912ecc314e5462affd74daf2e1b79239f8f65bfa30c8896f4acb9e1d787c240aeefe8cb09045b34ab2772d46aab4c42bb8cdb3374df247f1131a08758d0
|
|
7
|
+
data.tar.gz: 713df8fdefb6cd50b2c02408a9763da39e532b957d176fe5a8a6e1fbe265d2cf79457ae4d196d0e6ddfdf8effe0ca370c0297ea7186a5ce145717e4a93772be1
|
data/.github/workflows/CI.yml
CHANGED
|
@@ -13,50 +13,24 @@ jobs:
|
|
|
13
13
|
fail-fast: false
|
|
14
14
|
matrix:
|
|
15
15
|
ruby:
|
|
16
|
-
- '2.5'
|
|
17
16
|
- '2.6'
|
|
18
17
|
- '2.7'
|
|
19
18
|
- '3.0'
|
|
20
19
|
- '3.1'
|
|
21
20
|
gemfile:
|
|
22
|
-
- rails_5.2.3
|
|
23
|
-
- rails_5.2
|
|
24
21
|
- rails_6.0
|
|
25
22
|
- rails_6.1
|
|
26
23
|
- rails_7.0
|
|
27
|
-
- active_record_5.2.3
|
|
28
|
-
- active_record_5.2
|
|
29
24
|
- active_record_6.0
|
|
30
25
|
- active_record_6.1
|
|
31
26
|
- active_record_7.0
|
|
32
27
|
prepared_statements: [true, false]
|
|
33
28
|
exclude:
|
|
34
29
|
# activesupport-7.0.0 requires ruby version >= 2.7.0
|
|
35
|
-
- ruby: '2.5'
|
|
36
|
-
gemfile: 'rails_7.0'
|
|
37
|
-
- ruby: '2.5'
|
|
38
|
-
gemfile: 'active_record_7.0'
|
|
39
30
|
- ruby: '2.6'
|
|
40
31
|
gemfile: 'rails_7.0'
|
|
41
32
|
- ruby: '2.6'
|
|
42
33
|
gemfile: 'active_record_7.0'
|
|
43
|
-
# ruby >3 and activesupport 5.2 are not compatible
|
|
44
|
-
- ruby: '3.0'
|
|
45
|
-
gemfile: 'rails_5.2'
|
|
46
|
-
- ruby: '3.0'
|
|
47
|
-
gemfile: 'active_record_5.2'
|
|
48
|
-
- ruby: '3.1'
|
|
49
|
-
gemfile: 'rails_5.2'
|
|
50
|
-
- ruby: '3.1'
|
|
51
|
-
gemfile: 'active_record_5.2'
|
|
52
|
-
- ruby: '3.0'
|
|
53
|
-
gemfile: 'rails_5.2.3'
|
|
54
|
-
- ruby: '3.0'
|
|
55
|
-
gemfile: 'active_record_5.2.3'
|
|
56
|
-
- ruby: '3.1'
|
|
57
|
-
gemfile: 'rails_5.2.3'
|
|
58
|
-
- ruby: '3.1'
|
|
59
|
-
gemfile: 'active_record_5.2.3'
|
|
60
34
|
name: Ruby ${{ matrix.ruby }} / ${{ matrix.gemfile }} ${{ (matrix.prepared_statements && 'w/ prepared statements') || '' }}
|
|
61
35
|
env:
|
|
62
36
|
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
|
data/Appraisals
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
appraise 'rails-5.2' do
|
|
2
|
-
gem 'rails', '~> 5.2.0'
|
|
3
|
-
gem 'i18n', '~> 0.9.5'
|
|
4
|
-
gem 'nokogiri', '~> 1.7.1'
|
|
5
|
-
gem 'nio4r', '~> 2.3.1'
|
|
6
|
-
gem 'sprockets', '~> 3.7.1'
|
|
7
|
-
gem 'byebug', '~> 11.0'
|
|
8
|
-
gem 'rake', '12.0.0'
|
|
9
|
-
gem 'redis', '3.3.3'
|
|
10
|
-
gem 'pry-byebug', '3.9.0'
|
|
11
|
-
end
|
|
12
|
-
|
|
13
1
|
appraise 'rails-6.0' do
|
|
14
2
|
gem 'rails', '~> 6.0.3'
|
|
15
3
|
end
|
|
@@ -22,18 +10,6 @@ appraise 'rails-7.0' do
|
|
|
22
10
|
gem 'rails', '~> 7.0.0'
|
|
23
11
|
end
|
|
24
12
|
|
|
25
|
-
appraise 'active-record-5.2' do
|
|
26
|
-
gem 'activerecord', '~> 5.2.0'
|
|
27
|
-
gem 'i18n', '~> 0.9.5'
|
|
28
|
-
gem 'nokogiri', '~> 1.7.1'
|
|
29
|
-
gem 'nio4r', '~> 2.3.1'
|
|
30
|
-
gem 'sprockets', '~> 3.7.1'
|
|
31
|
-
gem 'byebug', '~> 11.0'
|
|
32
|
-
gem 'rake', '12.0.0'
|
|
33
|
-
gem 'redis', '3.3.3'
|
|
34
|
-
gem 'pry-byebug', '3.9.0'
|
|
35
|
-
end
|
|
36
|
-
|
|
37
13
|
appraise 'active-record-6.0' do
|
|
38
14
|
gem 'activerecord', '~> 6.0.3'
|
|
39
15
|
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.0 2022-12-06
|
|
4
|
+
* Handle changing tenant from `nil` to a value [#173](https://github.com/citusdata/activerecord-multi-tenant/pull/173)
|
|
5
|
+
* Allow Partitioned tables to be created without a primary key [#172](https://github.com/citusdata/activerecord-multi-tenant/pull/172)
|
|
6
|
+
* Only attempt to reload with MultiTenant when parition_key is present [#175](https://github.com/citusdata/activerecord-multi-tenant/pull/175)
|
|
7
|
+
* Remove support for Ruby 2.5 & ActiveRecord 5.2
|
|
8
|
+
|
|
9
|
+
## 2.1.6 2022-11-23
|
|
10
|
+
* Fix undefined wrap_methods error & wrap_methods version check [#170](https://github.com/citusdata/activerecord-multi-tenant/pull/170)
|
|
11
|
+
|
|
12
|
+
## 2.1.5 2022-11-20
|
|
13
|
+
* Fix `MultiTenant.without` codegen bug in Rails 6.1+ [#168](https://github.com/citusdata/activerecord-multi-tenant/pull/168)
|
|
14
|
+
|
|
15
|
+
## 2.1.4 2022-11-03
|
|
16
|
+
* Fixes #166 where db:schema:dump is broken when using this gem with MySQL [#167](https://github.com/citusdata/activerecord-multi-tenant/pull/167)
|
|
17
|
+
|
|
18
|
+
## 2.1.3 2022-10-27
|
|
19
|
+
* Error when calling a method that takes keyword arguments with MultiTenant.wrap_methods [#164](https://github.com/citusdata/activerecord-multi-tenant/pull/164)
|
|
20
|
+
|
|
21
|
+
## 2.1.2 2022-10-26
|
|
22
|
+
* Fixes issue when wraping methods that require a block [#162](https://github.com/citusdata/activerecord-multi-tenant/pull/162)
|
|
23
|
+
|
|
24
|
+
## 2.1.1 2022-10-20
|
|
25
|
+
* Fix query building for models with mismatched partition_keys [#150](https://github.com/citusdata/activerecord-multi-tenant/pull/150)
|
|
26
|
+
* Identify tenant even if class name is nonstandard [#152](https://github.com/citusdata/activerecord-multi-tenant/pull/152)
|
|
27
|
+
* Add current_tenant_id to WHERE clauses when calling methods on activerecord instance or its associations [#154](https://github.com/citusdata/activerecord-multi-tenant/pull/154)
|
|
28
|
+
* Make create_distributed_table, create_reference_table reversible & add ruby wrapper for rebalance_table_shards [#155](https://github.com/citusdata/activerecord-multi-tenant/pull/155)
|
|
29
|
+
* Support create_distributed_table, create_reference_table in schema.rb [#156](https://github.com/citusdata/activerecord-multi-tenant/pull/156)
|
|
30
|
+
* Add client and server sidekiq middleware to sidekiq middleware chain [#158](https://github.com/citusdata/activerecord-multi-tenant/pull/158)
|
|
31
|
+
|
|
3
32
|
## 2.0.0 2022-05-19
|
|
4
33
|
|
|
5
34
|
* Replace RequestStore with CurrentAttributes [#139](https://github.com/citusdata/activerecord-multi-tenant/pull/139)
|
data/README.md
CHANGED
|
@@ -16,7 +16,7 @@ gem 'activerecord-multi-tenant'
|
|
|
16
16
|
|
|
17
17
|
## Supported Rails versions
|
|
18
18
|
|
|
19
|
-
All Ruby on Rails versions starting with
|
|
19
|
+
All Ruby on Rails versions starting with 6.0 or newer (up to 7.0) are supported.
|
|
20
20
|
|
|
21
21
|
This gem only supports ActiveRecord (the Rails default ORM), and not alternative ORMs like Sequel.
|
|
22
22
|
|
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
|
15
15
|
s.homepage = 'https://github.com/citusdata/activerecord-multi-tenant'
|
|
16
16
|
s.license = 'MIT'
|
|
17
17
|
|
|
18
|
-
s.add_dependency 'rails', '>=
|
|
18
|
+
s.add_dependency 'rails', '>= 6'
|
|
19
19
|
|
|
20
20
|
s.add_development_dependency 'rspec', '>= 3.0'
|
|
21
21
|
s.add_development_dependency 'rspec-rails'
|
|
@@ -2,12 +2,40 @@ module MultiTenant
|
|
|
2
2
|
module MigrationExtensions
|
|
3
3
|
def create_distributed_table(table_name, partition_key)
|
|
4
4
|
return unless citus_version.present?
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
reversible do |dir|
|
|
7
|
+
dir.up do
|
|
8
|
+
execute "SELECT create_distributed_table($$#{table_name}$$, $$#{partition_key}$$)"
|
|
9
|
+
end
|
|
10
|
+
dir.down do
|
|
11
|
+
undistribute_table(table_name)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
6
14
|
end
|
|
7
15
|
|
|
8
16
|
def create_reference_table(table_name)
|
|
9
17
|
return unless citus_version.present?
|
|
10
|
-
|
|
18
|
+
|
|
19
|
+
reversible do |dir|
|
|
20
|
+
dir.up do
|
|
21
|
+
execute "SELECT create_reference_table($$#{table_name}$$)"
|
|
22
|
+
end
|
|
23
|
+
dir.down do
|
|
24
|
+
undistribute_table(table_name)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def undistribute_table(table_name)
|
|
30
|
+
return unless citus_version.present?
|
|
31
|
+
|
|
32
|
+
execute "SELECT undistribute_table($$#{table_name}$$))"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def rebalance_table_shards
|
|
36
|
+
return unless citus_version.present?
|
|
37
|
+
|
|
38
|
+
execute 'SELECT rebalance_table_shards()'
|
|
11
39
|
end
|
|
12
40
|
|
|
13
41
|
def execute_on_all_nodes(sql)
|
|
@@ -28,24 +56,22 @@ module MultiTenant
|
|
|
28
56
|
end
|
|
29
57
|
|
|
30
58
|
def citus_version
|
|
31
|
-
execute("SELECT extversion FROM pg_extension WHERE extname = 'citus'").getvalue(0,0).try(:split, '-').try(:first)
|
|
59
|
+
execute("SELECT extversion FROM pg_extension WHERE extname = 'citus'").getvalue(0, 0).try(:split, '-').try(:first)
|
|
32
60
|
rescue ArgumentError => e
|
|
33
|
-
raise unless e.message ==
|
|
61
|
+
raise unless e.message == 'invalid tuple number 0'
|
|
34
62
|
end
|
|
35
63
|
end
|
|
36
64
|
end
|
|
37
65
|
|
|
38
|
-
if defined?(ActiveRecord::Migration)
|
|
39
|
-
ActiveRecord::Migration.send(:include, MultiTenant::MigrationExtensions)
|
|
40
|
-
end
|
|
66
|
+
ActiveRecord::Migration.include MultiTenant::MigrationExtensions if defined?(ActiveRecord::Migration)
|
|
41
67
|
|
|
42
68
|
module ActiveRecord
|
|
43
69
|
module ConnectionAdapters # :nodoc:
|
|
44
70
|
module SchemaStatements
|
|
45
|
-
alias
|
|
71
|
+
alias orig_create_table create_table
|
|
46
72
|
def create_table(table_name, options = {}, &block)
|
|
47
73
|
ret = orig_create_table(table_name, **options.except(:partition_key), &block)
|
|
48
|
-
if options[:partition_key] && options[:partition_key].to_s != 'id'
|
|
74
|
+
if options[:id] != false && options[:partition_key] && options[:partition_key].to_s != 'id'
|
|
49
75
|
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{table_name}_pkey"
|
|
50
76
|
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(\"#{options[:partition_key]}\", id)"
|
|
51
77
|
end
|
|
@@ -54,3 +80,44 @@ module ActiveRecord
|
|
|
54
80
|
end
|
|
55
81
|
end
|
|
56
82
|
end
|
|
83
|
+
|
|
84
|
+
module ActiveRecord
|
|
85
|
+
class SchemaDumper
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
alias initialize_without_citus initialize
|
|
89
|
+
def initialize(connection, options = {})
|
|
90
|
+
initialize_without_citus(connection, options)
|
|
91
|
+
|
|
92
|
+
citus_version = begin
|
|
93
|
+
ActiveRecord::Migration.citus_version
|
|
94
|
+
rescue StandardError
|
|
95
|
+
# Handle the case where this gem is used with MySQL https://github.com/citusdata/activerecord-multi-tenant/issues/166
|
|
96
|
+
nil
|
|
97
|
+
end
|
|
98
|
+
@distribution_columns =
|
|
99
|
+
if citus_version.present?
|
|
100
|
+
@connection.execute('SELECT logicalrelid::regclass AS table_name, column_to_column_name(logicalrelid, partkey) AS dist_col_name FROM pg_dist_partition').to_h do |v|
|
|
101
|
+
[v['table_name'], v['dist_col_name']]
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
{}
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Support for create_distributed_table & create_reference_table
|
|
109
|
+
alias table_without_citus table
|
|
110
|
+
def table(table, stream)
|
|
111
|
+
table_without_citus(table, stream)
|
|
112
|
+
table_name = remove_prefix_and_suffix(table)
|
|
113
|
+
distribution_column = @distribution_columns[table_name]
|
|
114
|
+
if distribution_column
|
|
115
|
+
stream.puts " create_distributed_table(#{table_name.inspect}, #{distribution_column.inspect})"
|
|
116
|
+
stream.puts
|
|
117
|
+
elsif @distribution_columns.key?(table_name)
|
|
118
|
+
stream.puts " create_reference_table(#{table_name.inspect})"
|
|
119
|
+
stream.puts
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
require_relative './multi_tenant'
|
|
2
|
+
|
|
1
3
|
module MultiTenant
|
|
2
4
|
module ModelExtensionsClassMethods
|
|
3
5
|
DEFAULT_ID_FIELD = 'id'.freeze
|
|
4
6
|
|
|
5
7
|
def multi_tenant(tenant_name, options = {})
|
|
6
|
-
if to_s.underscore.to_sym == tenant_name
|
|
8
|
+
if to_s.underscore.to_sym == tenant_name || (!table_name.nil? && table_name.singularize.to_sym == tenant_name)
|
|
7
9
|
unless MultiTenant.with_write_only_mode_enabled?
|
|
8
10
|
# This is the tenant model itself. Workaround for https://github.com/citusdata/citus/issues/687
|
|
9
11
|
before_create -> do
|
|
@@ -73,7 +75,6 @@ module MultiTenant
|
|
|
73
75
|
# Rails 5 `attribute_will_change!` uses the attribute-method-call rather than `read_attribute`
|
|
74
76
|
# and will raise ActiveModel::MissingAttributeError if that column was not selected.
|
|
75
77
|
# This is rescued as NoMethodError and in MRI attribute_was is assigned an arbitrary Object
|
|
76
|
-
# This is still true after the Rails 5.2 refactor
|
|
77
78
|
was = send("#{partition_key}_was")
|
|
78
79
|
was_nil_or_skipped = was.nil? || was.class == Object
|
|
79
80
|
|
|
@@ -100,7 +101,8 @@ module MultiTenant
|
|
|
100
101
|
include to_include
|
|
101
102
|
|
|
102
103
|
around_save -> (record, block) {
|
|
103
|
-
|
|
104
|
+
record_tenant = record.attribute_was(partition_key)
|
|
105
|
+
if persisted? && MultiTenant.current_tenant_id.nil? && !record_tenant.nil?
|
|
104
106
|
MultiTenant.with(record.public_send(partition_key)) { block.call }
|
|
105
107
|
else
|
|
106
108
|
block.call
|
|
@@ -108,7 +110,8 @@ module MultiTenant
|
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
around_update -> (record, block) {
|
|
111
|
-
|
|
113
|
+
record_tenant = record.attribute_was(partition_key)
|
|
114
|
+
if MultiTenant.current_tenant_id.nil? && !record_tenant.nil?
|
|
112
115
|
MultiTenant.with(record.public_send(partition_key)) { block.call }
|
|
113
116
|
else
|
|
114
117
|
block.call
|
|
@@ -129,6 +132,20 @@ end
|
|
|
129
132
|
|
|
130
133
|
ActiveSupport.on_load(:active_record) do |base|
|
|
131
134
|
base.extend MultiTenant::ModelExtensionsClassMethods
|
|
135
|
+
|
|
136
|
+
# Ensure we have current_tenant_id in where clause when a cached ActiveRecord instance is being reloaded, or update_columns without callbacks is called
|
|
137
|
+
MultiTenant.wrap_methods(ActiveRecord::Base, 'self', :delete, :reload, :update_columns)
|
|
138
|
+
|
|
139
|
+
# Any queuries fired for fetching a singular association have the correct current_tenant_id in WHERE clause
|
|
140
|
+
# reload is called anytime any record's association is accessed
|
|
141
|
+
MultiTenant.wrap_methods(ActiveRecord::Associations::Association, 'owner', :reload)
|
|
142
|
+
|
|
143
|
+
# For collection associations, we need to wrap multiple methods in returned proxy so that any queries have the correct current_tenant_id in WHERE clause
|
|
144
|
+
ActiveRecord::Associations::CollectionProxy.alias_method :equals_mt, :== # Hack to prevent syntax error due to invalid method name
|
|
145
|
+
ActiveRecord::Associations::CollectionProxy.alias_method :append_mt, :<< # Hack to prevent syntax error due to invalid method name
|
|
146
|
+
MultiTenant.wrap_methods(ActiveRecord::Associations::CollectionProxy, '@association.owner', :find, :last, :take, :build, :create, :create!, :replace, :delete_all, :destroy_all, :delete, :destroy, :calculate, :pluck, :size, :empty?, :include?, :equals_mt, :records, :append_mt, :find_nth_with_limit, :find_nth_from_last, :null_scope?, :find_from_target?, :exec_queries)
|
|
147
|
+
ActiveRecord::Associations::CollectionProxy.alias_method :==, :equals_mt
|
|
148
|
+
ActiveRecord::Associations::CollectionProxy.alias_method :<<, :append_mt
|
|
132
149
|
end
|
|
133
150
|
|
|
134
151
|
class ActiveRecord::Associations::Association
|
|
@@ -109,6 +109,41 @@ module MultiTenant
|
|
|
109
109
|
end
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
+
# Wrap calls to any of `method_names` on an instance Class `klass` with MultiTenant.with when `'owner'` (evaluated in context of the klass instance) is a ActiveRecord model instance that is multi-tenant
|
|
113
|
+
if Gem::Version.create(RUBY_VERSION) < Gem::Version.new('3.0.0')
|
|
114
|
+
def self.wrap_methods(klass, owner, *method_names)
|
|
115
|
+
method_names.each do |method_name|
|
|
116
|
+
original_method_name = :"_mt_original_#{method_name}"
|
|
117
|
+
klass.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
|
118
|
+
alias_method :#{original_method_name}, :#{method_name}
|
|
119
|
+
def #{method_name}(*args, &block)
|
|
120
|
+
if MultiTenant.multi_tenant_model_for_table(#{owner}.class.table_name).present? && #{owner}.persisted? && MultiTenant.current_tenant_id.nil? && #{owner}.class.respond_to?(:partition_key) && #{owner}.attributes.include?(#{owner}.class.partition_key)
|
|
121
|
+
MultiTenant.with(#{owner}.public_send(#{owner}.class.partition_key)) { #{original_method_name}(*args, &block) }
|
|
122
|
+
else
|
|
123
|
+
#{original_method_name}(*args, &block)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
CODE
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
else
|
|
130
|
+
def self.wrap_methods(klass, owner, *method_names)
|
|
131
|
+
method_names.each do |method_name|
|
|
132
|
+
original_method_name = :"_mt_original_#{method_name}"
|
|
133
|
+
klass.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
|
134
|
+
alias_method :#{original_method_name}, :#{method_name}
|
|
135
|
+
def #{method_name}(...)
|
|
136
|
+
if MultiTenant.multi_tenant_model_for_table(#{owner}.class.table_name).present? && #{owner}.persisted? && MultiTenant.current_tenant_id.nil? && #{owner}.class.respond_to?(:partition_key) && #{owner}.attributes.include?(#{owner}.class.partition_key)
|
|
137
|
+
MultiTenant.with(#{owner}.public_send(#{owner}.class.partition_key)) { #{original_method_name}(...) }
|
|
138
|
+
else
|
|
139
|
+
#{original_method_name}(...)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
CODE
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
112
147
|
# Preserve backward compatibility for people using .with_id
|
|
113
148
|
singleton_class.send(:alias_method, :with_id, :with)
|
|
114
149
|
|
|
@@ -305,7 +305,7 @@ module ActiveRecord
|
|
|
305
305
|
model_right = MultiTenant.multi_tenant_model_for_table(relation_left.table_name)
|
|
306
306
|
model_left = MultiTenant.multi_tenant_model_for_table(relation_right.table_name)
|
|
307
307
|
if model_right && model_left
|
|
308
|
-
join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(
|
|
308
|
+
join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(relation_right[model_right.partition_key], relation_left)
|
|
309
309
|
node_join.right.expr = node_join.right.expr.and(join_enforcement_clause)
|
|
310
310
|
end
|
|
311
311
|
end
|
|
@@ -330,8 +330,9 @@ module ActiveRecord
|
|
|
330
330
|
return nil, nil
|
|
331
331
|
end
|
|
332
332
|
|
|
333
|
-
|
|
334
|
-
|
|
333
|
+
child = children.first.respond_to?(:children) ? children.first.children.first : children.first
|
|
334
|
+
if child.right.respond_to?(:relation) && child.left.respond_to?(:relation)
|
|
335
|
+
return child.right.relation, child.left.relation
|
|
335
336
|
end
|
|
336
337
|
|
|
337
338
|
return nil, nil
|
|
@@ -33,6 +33,22 @@ module Sidekiq::Middleware::MultiTenant
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
Sidekiq.configure_server do |config|
|
|
37
|
+
config.server_middleware do |chain|
|
|
38
|
+
chain.add Sidekiq::Middleware::MultiTenant::Server
|
|
39
|
+
end
|
|
40
|
+
config.client_middleware do |chain|
|
|
41
|
+
chain.add Sidekiq::Middleware::MultiTenant::Client
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Sidekiq.configure_client do |config|
|
|
46
|
+
config.client_middleware do |chain|
|
|
47
|
+
chain.add Sidekiq::Middleware::MultiTenant::Client
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
36
52
|
module Sidekiq
|
|
37
53
|
class Client
|
|
38
54
|
def push_bulk_with_tenants(items)
|
|
@@ -10,4 +10,3 @@ 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'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe MultiTenant, 'Association methods' do
|
|
4
|
+
let(:account1) { Account.create! name: 'test1' }
|
|
5
|
+
let(:account2) { Account.create! name: 'test2' }
|
|
6
|
+
let(:project1) { Project.create! name: 'something1', account: account1 }
|
|
7
|
+
let(:project2) { Project.create! name: 'something2', account: account2, id: project1.id }
|
|
8
|
+
let(:task1) { Task.create! name: 'task1', project: project1, account: account1 }
|
|
9
|
+
let(:task2) { Task.create! name: 'task2', project: project2, account: account2, id: task1.id }
|
|
10
|
+
|
|
11
|
+
context 'include the tenant_id in queries and' do
|
|
12
|
+
it 'creates a task with correct account_id' do
|
|
13
|
+
expect(project2.tasks.create(name: 'task3').account_id).to eq(account2.id)
|
|
14
|
+
end
|
|
15
|
+
it 'return correct account_id' do
|
|
16
|
+
expect(task1.project.account_id).to_not eq(task2.project.account_id) # belongs_to
|
|
17
|
+
expect(project2.tasks.count).to eq(1)
|
|
18
|
+
expect(project2.tasks.first.account_id).to eq(account2.id) # has_many
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -70,6 +70,24 @@ describe MultiTenant do
|
|
|
70
70
|
it { expect(@partition_key_not_model_task.non_model_id).to be 77 }
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
|
|
74
|
+
describe 'Tenant model with a nonstandard class name' do
|
|
75
|
+
let(:account_klass) do
|
|
76
|
+
Class.new(ActiveRecord::Base) do
|
|
77
|
+
self.table_name = 'account'
|
|
78
|
+
def self.name
|
|
79
|
+
'UserAccount'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
multi_tenant(:account)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
it "does not register the tenant model" do
|
|
86
|
+
expect(MultiTenant).not_to receive(:register_multi_tenant_model)
|
|
87
|
+
account_klass
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
73
91
|
describe 'Changes table_name after multi_tenant called' do
|
|
74
92
|
before do
|
|
75
93
|
account_klass.has_many(:posts, anonymous_class: post_klass)
|
|
@@ -186,13 +204,19 @@ describe MultiTenant do
|
|
|
186
204
|
end
|
|
187
205
|
|
|
188
206
|
it 'handles belongs_to with optional: true' do
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
207
|
+
record = OptionalSubTask.create(sub_task_id: sub_task.id)
|
|
208
|
+
expect(record.reload.sub_task).to eq(sub_task)
|
|
209
|
+
expect(record.account_id).to eq(nil)
|
|
210
|
+
end
|
|
192
211
|
|
|
193
|
-
|
|
212
|
+
it 'handles changing tenant from nil to a value' do
|
|
213
|
+
record = OptionalSubTask.create(sub_task_id: sub_task.id)
|
|
194
214
|
expect(record.reload.sub_task).to eq(sub_task)
|
|
195
215
|
expect(record.account_id).to eq(nil)
|
|
216
|
+
|
|
217
|
+
record.account = account
|
|
218
|
+
record.save!
|
|
219
|
+
expect(record.reload.account_id).to eq(account.id)
|
|
196
220
|
end
|
|
197
221
|
|
|
198
222
|
it 'handles has_many through' do
|
|
@@ -285,6 +309,55 @@ describe MultiTenant do
|
|
|
285
309
|
end
|
|
286
310
|
end
|
|
287
311
|
|
|
312
|
+
# Joins
|
|
313
|
+
describe 'joins for models' do
|
|
314
|
+
context 'for models with where condition in associations' do
|
|
315
|
+
let(:account) { Account.create!(name: 'Account 1') }
|
|
316
|
+
|
|
317
|
+
it 'should add tenant condition to the queries when tenant is set' do
|
|
318
|
+
expected_join_sql = <<-SQL.strip
|
|
319
|
+
SELECT "comments".* FROM "comments" INNER JOIN "tasks" ON "tasks"."id" = "comments"."commentable_id" AND "comments"."commentable_type" = 'Task' AND "tasks"."account_id" = 1 WHERE "comments"."account_id" = 1
|
|
320
|
+
SQL
|
|
321
|
+
|
|
322
|
+
MultiTenant.with(account) do
|
|
323
|
+
expect(Comment.joins(:task).to_sql).to eq(expected_join_sql)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it 'should add tenant condition to the queries when tenant is not set' do
|
|
328
|
+
MultiTenant.without do
|
|
329
|
+
expected_join_sql = <<-SQL.strip
|
|
330
|
+
SELECT "comments".* FROM "comments" INNER JOIN "tasks" ON "tasks"."id" = "comments"."commentable_id" AND "comments"."commentable_type" = 'Task' AND "comments"."account_id" = "tasks"."account_id"
|
|
331
|
+
SQL
|
|
332
|
+
expect(Comment.joins(:task).to_sql).to eq(expected_join_sql)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
context 'for models with default associations' do
|
|
338
|
+
let(:account) { Account.create!(name: 'Account 1') }
|
|
339
|
+
|
|
340
|
+
it 'should add tenant condition to the queries when tenant is set' do
|
|
341
|
+
expected_join_sql = <<-SQL.strip
|
|
342
|
+
SELECT "projects".* FROM "projects" INNER JOIN "tasks" ON "tasks"."project_id" = "projects"."id" AND "tasks"."account_id" = 1 WHERE "projects"."account_id" = 1
|
|
343
|
+
SQL
|
|
344
|
+
|
|
345
|
+
MultiTenant.with(account) do
|
|
346
|
+
expect(Project.joins(:tasks).to_sql).to eq(expected_join_sql)
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it 'should add tenant condition to the queries when tenant is not set' do
|
|
351
|
+
MultiTenant.without do
|
|
352
|
+
expected_join_sql = <<-SQL.strip
|
|
353
|
+
SELECT "projects".* FROM "projects" INNER JOIN "tasks" ON "tasks"."project_id" = "projects"."id" AND "projects"."account_id" = "tasks"."account_id"
|
|
354
|
+
SQL
|
|
355
|
+
expect(Project.joins(:tasks).to_sql).to eq(expected_join_sql)
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
288
361
|
# ::with
|
|
289
362
|
describe "::with" do
|
|
290
363
|
it "should set current_tenant to the specified tenant inside the block" do
|
|
@@ -400,10 +473,10 @@ describe MultiTenant do
|
|
|
400
473
|
|
|
401
474
|
it "applies the team_id conditions in the where clause" do
|
|
402
475
|
option1 = <<-sql.strip
|
|
403
|
-
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "
|
|
476
|
+
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "tasks"."account_id" = "sub_tasks"."account_id" WHERE "tasks"."project_id" = 1 AND "sub_tasks"."account_id" = 1 AND "tasks"."account_id" = 1
|
|
404
477
|
sql
|
|
405
478
|
option2 = <<-sql.strip
|
|
406
|
-
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "
|
|
479
|
+
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "tasks"."account_id" = "sub_tasks"."account_id" WHERE "sub_tasks"."account_id" = 1 AND "tasks"."project_id" = 1 AND "tasks"."account_id" = 1
|
|
407
480
|
sql
|
|
408
481
|
|
|
409
482
|
account1 = Account.create! name: 'Account 1'
|
|
@@ -418,7 +491,7 @@ describe MultiTenant do
|
|
|
418
491
|
|
|
419
492
|
MultiTenant.without do
|
|
420
493
|
expected_sql = <<-sql
|
|
421
|
-
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "
|
|
494
|
+
SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "tasks"."account_id" = "sub_tasks"."account_id" WHERE "tasks"."project_id" = 1
|
|
422
495
|
sql
|
|
423
496
|
|
|
424
497
|
project = Project.first
|
|
@@ -456,7 +529,7 @@ describe MultiTenant do
|
|
|
456
529
|
expect(project.categories).to include(category1)
|
|
457
530
|
|
|
458
531
|
expected_sql = <<-sql
|
|
459
|
-
SELECT "projects".* FROM "projects" INNER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "
|
|
532
|
+
SELECT "projects".* FROM "projects" INNER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = "project_categories"."account_id" INNER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" WHERE "projects"."account_id" = 1
|
|
460
533
|
sql
|
|
461
534
|
|
|
462
535
|
expect(Project.where(account_id: 1).joins(:categories).to_sql).to eq(expected_sql.strip)
|
|
@@ -490,7 +563,7 @@ describe MultiTenant do
|
|
|
490
563
|
|
|
491
564
|
MultiTenant.without do
|
|
492
565
|
expected_sql = <<-sql
|
|
493
|
-
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "
|
|
566
|
+
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = "project_categories"."account_id" LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" WHERE "projects"."account_id" = 1
|
|
494
567
|
sql
|
|
495
568
|
|
|
496
569
|
expect(Project.where(account_id: 1).eager_load(:categories).to_sql).to eq(expected_sql.strip)
|
|
@@ -522,7 +595,7 @@ describe MultiTenant do
|
|
|
522
595
|
|
|
523
596
|
MultiTenant.without do
|
|
524
597
|
expected_sql = <<-sql
|
|
525
|
-
SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "
|
|
598
|
+
SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "tasks"."account_id" = "projects"."account_id" LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
|
|
526
599
|
sql
|
|
527
600
|
|
|
528
601
|
expect(Task.where(account_id: 1).joins(:project).joins('LEFT JOIN project_categories pc ON project.category_id = pc.id').to_sql).to eq(expected_sql.strip)
|
|
@@ -54,6 +54,25 @@ describe MultiTenant, 'Record modifications' do
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
it 'should not update other objects with same id when calling object.update_columns' do
|
|
58
|
+
# When two records with same id but different account_id are updated, it should only update the current one
|
|
59
|
+
expect(project.account).to eq(account)
|
|
60
|
+
expect(project2.account).to eq(account2)
|
|
61
|
+
expect(project.id).to eq(project2.id)
|
|
62
|
+
|
|
63
|
+
MultiTenant.without do
|
|
64
|
+
project2.update_columns(name: 'newthing2')
|
|
65
|
+
expect(project.reload.name).to eq('something')
|
|
66
|
+
expect(project2.reload.name).to eq('newthing2')
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'should return the same object when calling object.reload' do
|
|
71
|
+
# When two records with same id but different account_id are updated, it should not return the other object
|
|
72
|
+
expect(project.reload.account_id).to eq(account.id)
|
|
73
|
+
expect(project2.reload.account_id).to eq(account2.id)
|
|
74
|
+
end
|
|
75
|
+
|
|
57
76
|
it 'test delete for reference tables' do
|
|
58
77
|
category1 = Category.create! name: 'Category 1'
|
|
59
78
|
expect(Category.count).to eq(1)
|
data/spec/schema.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-multi-tenant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Citus Data
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-12-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '6'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '6'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rspec
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -154,13 +154,9 @@ files:
|
|
|
154
154
|
- activerecord-multi-tenant.gemspec
|
|
155
155
|
- docker-compose.yml
|
|
156
156
|
- gemfiles/.bundle/config
|
|
157
|
-
- gemfiles/active_record_5.2.3.gemfile
|
|
158
|
-
- gemfiles/active_record_5.2.gemfile
|
|
159
157
|
- gemfiles/active_record_6.0.gemfile
|
|
160
158
|
- gemfiles/active_record_6.1.gemfile
|
|
161
159
|
- gemfiles/active_record_7.0.gemfile
|
|
162
|
-
- gemfiles/rails_5.2.3.gemfile
|
|
163
|
-
- gemfiles/rails_5.2.gemfile
|
|
164
160
|
- gemfiles/rails_6.0.gemfile
|
|
165
161
|
- gemfiles/rails_6.1.gemfile
|
|
166
162
|
- gemfiles/rails_7.0.gemfile
|
|
@@ -172,12 +168,12 @@ files:
|
|
|
172
168
|
- lib/activerecord-multi-tenant/migrations.rb
|
|
173
169
|
- lib/activerecord-multi-tenant/model_extensions.rb
|
|
174
170
|
- lib/activerecord-multi-tenant/multi_tenant.rb
|
|
175
|
-
- lib/activerecord-multi-tenant/persistence_extension.rb
|
|
176
171
|
- lib/activerecord-multi-tenant/query_monitor.rb
|
|
177
172
|
- lib/activerecord-multi-tenant/query_rewriter.rb
|
|
178
173
|
- lib/activerecord-multi-tenant/sidekiq.rb
|
|
179
174
|
- lib/activerecord-multi-tenant/version.rb
|
|
180
175
|
- lib/activerecord-multi-tenant/with_lock.rb
|
|
176
|
+
- spec/activerecord-multi-tenant/associations_spec.rb
|
|
181
177
|
- spec/activerecord-multi-tenant/controller_extensions_spec.rb
|
|
182
178
|
- spec/activerecord-multi-tenant/fast_truncate_spec.rb
|
|
183
179
|
- spec/activerecord-multi-tenant/model_extensions_spec.rb
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gem "appraisal"
|
|
6
|
-
gem "activerecord", "~> 5.2.0", "< 5.2.4" # FIXME
|
|
7
|
-
gem "i18n", "~> 0.9.5"
|
|
8
|
-
gem "nokogiri", "~> 1.7.1"
|
|
9
|
-
gem "nio4r", "~> 2.3.1"
|
|
10
|
-
gem "sprockets", "~> 3.7.1"
|
|
11
|
-
gem "byebug", "~> 11.0"
|
|
12
|
-
gem "rake", "12.0.0"
|
|
13
|
-
gem "redis", "3.3.3"
|
|
14
|
-
gem "pry-byebug", "3.9.0"
|
|
15
|
-
|
|
16
|
-
gemspec path: "../"
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gem "appraisal"
|
|
6
|
-
gem "activerecord", "~> 5.2.0"
|
|
7
|
-
gem "i18n", "~> 0.9.5"
|
|
8
|
-
gem "nokogiri", "~> 1.7.1"
|
|
9
|
-
gem "nio4r", "~> 2.3.1"
|
|
10
|
-
gem "sprockets", "~> 3.7.1"
|
|
11
|
-
gem "byebug", "~> 11.0"
|
|
12
|
-
gem "rake", "12.0.0"
|
|
13
|
-
gem "redis", "3.3.3"
|
|
14
|
-
gem "pry-byebug", "3.9.0"
|
|
15
|
-
|
|
16
|
-
gemspec path: "../"
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gem "appraisal"
|
|
6
|
-
gem "rails", "~> 5.2.0", "< 5.2.4" # FIXME
|
|
7
|
-
gem "i18n", "~> 0.9.5"
|
|
8
|
-
gem "nokogiri", "~> 1.7.1"
|
|
9
|
-
gem "nio4r", "~> 2.3.1"
|
|
10
|
-
gem "sprockets", "~> 3.7.1"
|
|
11
|
-
gem "byebug", "~> 11.0"
|
|
12
|
-
gem "rake", "12.0.0"
|
|
13
|
-
gem "redis", "3.3.3"
|
|
14
|
-
gem "pry-byebug", "3.9.0"
|
|
15
|
-
|
|
16
|
-
gemspec path: "../"
|
data/gemfiles/rails_5.2.gemfile
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gem "appraisal"
|
|
6
|
-
gem "rails", "~> 5.2.0"
|
|
7
|
-
gem "i18n", "~> 0.9.5"
|
|
8
|
-
gem "nokogiri", "~> 1.7.1"
|
|
9
|
-
gem "nio4r", "~> 2.3.1"
|
|
10
|
-
gem "sprockets", "~> 3.7.1"
|
|
11
|
-
gem "byebug", "~> 11.0"
|
|
12
|
-
gem "rake", "12.0.0"
|
|
13
|
-
gem "redis", "3.3.3"
|
|
14
|
-
gem "pry-byebug", "3.9.0"
|
|
15
|
-
|
|
16
|
-
gemspec path: "../"
|
|
@@ -1,13 +0,0 @@
|
|
|
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
|