activerecord-multi-tenant 1.2.0 → 2.2.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: fa2e595cc76e33a877613504121106791680118da0a0c4957ff1190e75e99c3a
4
- data.tar.gz: 8a232e3431462d5b8b3972f0825664c210cc51729b2e94d08c5529851365d7f8
3
+ metadata.gz: 15ad19bf20781129dc1bd57d4e4b8eb8731044cea3b89f29a62789d0f5a45aee
4
+ data.tar.gz: 0f76290b00a7d540495972ab5a9de09d3abbb1dde11758d58b08493bf743b5da
5
5
  SHA512:
6
- metadata.gz: a2df2315ca041de29d2e82786a33904a9ac1dedd3f1ee4a2e470822cff977e9f4548ab0d33bd6eefec8055b9fc74ff8db2fdcf4c93cba4992aaaa681dcd1a695
7
- data.tar.gz: 9da5eec93a1bcd33bff29ab1e0035022592802f512d27139608e92988a17365d3fe4cff0a73fc0f83e9513cea9dd2bf6233bb4deac9533320fb0884f7ef8b219
6
+ metadata.gz: 17f7b912ecc314e5462affd74daf2e1b79239f8f65bfa30c8896f4acb9e1d787c240aeefe8cb09045b34ab2772d46aab4c42bb8cdb3374df247f1131a08758d0
7
+ data.tar.gz: 713df8fdefb6cd50b2c02408a9763da39e532b957d176fe5a8a6e1fbe265d2cf79457ae4d196d0e6ddfdf8effe0ca370c0297ea7186a5ce145717e4a93772be1
@@ -13,40 +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
23
21
  - rails_6.0
24
22
  - rails_6.1
25
23
  - rails_7.0
26
- - active_record_5.2
27
24
  - active_record_6.0
28
25
  - active_record_6.1
29
26
  - active_record_7.0
30
27
  prepared_statements: [true, false]
31
28
  exclude:
32
29
  # activesupport-7.0.0 requires ruby version >= 2.7.0
33
- - ruby: '2.5'
34
- gemfile: 'rails_7.0'
35
- - ruby: '2.5'
36
- gemfile: 'active_record_7.0'
37
30
  - ruby: '2.6'
38
31
  gemfile: 'rails_7.0'
39
32
  - ruby: '2.6'
40
33
  gemfile: 'active_record_7.0'
41
- # ruby >3 and activesupport 5.2 are not compatible
42
- - ruby: '3.0'
43
- gemfile: 'rails_5.2'
44
- - ruby: '3.0'
45
- gemfile: 'active_record_5.2'
46
- - ruby: '3.1'
47
- gemfile: 'rails_5.2'
48
- - ruby: '3.1'
49
- gemfile: 'active_record_5.2'
50
34
  name: Ruby ${{ matrix.ruby }} / ${{ matrix.gemfile }} ${{ (matrix.prepared_statements && 'w/ prepared statements') || '' }}
51
35
  env:
52
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,43 @@
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
+
32
+ ## 2.0.0 2022-05-19
33
+
34
+ * Replace RequestStore with CurrentAttributes [#139](https://github.com/citusdata/activerecord-multi-tenant/pull/139)
35
+ * Support changing table_name after calling multi_tenant [#128](https://github.com/citusdata/activerecord-multi-tenant/pull/128)
36
+ * Allow to use uuid as primary key on partition table [#112](https://github.com/citusdata/activerecord-multi-tenant/pull/112)
37
+ * Support latest Rails 5.2 [#145](https://github.com/citusdata/activerecord-multi-tenant/pull/145)
38
+ * Support optional: true for belongs_to [#147](https://github.com/citusdata/activerecord-multi-tenant/pull/147)
39
+
40
+
3
41
  ## 1.2.0 2022-03-29
4
42
 
5
43
  * Test Rails 7 & Ruby 3
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 4.2 or newer (up to 6.0) are supported.
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,8 +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_runtime_dependency('request_store', '>= 1.0.5')
19
- s.add_dependency('rails','>= 4.2')
18
+ s.add_dependency 'rails', '>= 6'
20
19
 
21
20
  s.add_development_dependency 'rspec', '>= 3.0'
22
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
- execute "SELECT create_distributed_table($$#{table_name}$$, $$#{partition_key}$$)"
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
- execute "SELECT create_reference_table($$#{table_name}$$)"
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 == "invalid tuple number 0"
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 :orig_create_table :create_table
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,12 +1,20 @@
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
- before_create -> { self.id ||= self.class.connection.select_value("SELECT nextval('" + [self.class.table_name, self.class.primary_key, 'seq'].join('_') + "'::regclass)") }
11
+ before_create -> do
12
+ if self.class.columns_hash[self.class.primary_key].type == :uuid
13
+ self.id ||= SecureRandom.uuid
14
+ else
15
+ self.id ||= self.class.connection.select_value("SELECT nextval('#{self.class.table_name}_#{self.class.primary_key}_seq'::regclass)")
16
+ end
17
+ end
10
18
  end
11
19
  else
12
20
  class << self
@@ -38,18 +46,18 @@ module MultiTenant
38
46
 
39
47
  def inherited(subclass)
40
48
  super
41
- MultiTenant.register_multi_tenant_model(subclass.table_name, subclass) if subclass.table_name
49
+ MultiTenant.register_multi_tenant_model(subclass)
42
50
  end
43
51
  end
44
52
 
45
- MultiTenant.register_multi_tenant_model(table_name, self) if table_name
53
+ MultiTenant.register_multi_tenant_model(self)
46
54
 
47
55
  @partition_key = options[:partition_key] || MultiTenant.partition_key(tenant_name)
48
56
  partition_key = @partition_key
49
57
 
50
58
  # Create an implicit belongs_to association only if tenant class exists
51
59
  if MultiTenant.tenant_klass_defined?(tenant_name)
52
- belongs_to tenant_name, **options.slice(:class_name, :inverse_of).merge(foreign_key: options[:partition_key])
60
+ belongs_to tenant_name, **options.slice(:class_name, :inverse_of, :optional).merge(foreign_key: options[:partition_key])
53
61
  end
54
62
 
55
63
  # New instances should have the tenant set
@@ -67,7 +75,6 @@ module MultiTenant
67
75
  # Rails 5 `attribute_will_change!` uses the attribute-method-call rather than `read_attribute`
68
76
  # and will raise ActiveModel::MissingAttributeError if that column was not selected.
69
77
  # This is rescued as NoMethodError and in MRI attribute_was is assigned an arbitrary Object
70
- # This is still true after the Rails 5.2 refactor
71
78
  was = send("#{partition_key}_was")
72
79
  was_nil_or_skipped = was.nil? || was.class == Object
73
80
 
@@ -94,7 +101,8 @@ module MultiTenant
94
101
  include to_include
95
102
 
96
103
  around_save -> (record, block) {
97
- if persisted? && MultiTenant.current_tenant_id.nil?
104
+ record_tenant = record.attribute_was(partition_key)
105
+ if persisted? && MultiTenant.current_tenant_id.nil? && !record_tenant.nil?
98
106
  MultiTenant.with(record.public_send(partition_key)) { block.call }
99
107
  else
100
108
  block.call
@@ -102,7 +110,8 @@ module MultiTenant
102
110
  }
103
111
 
104
112
  around_update -> (record, block) {
105
- if MultiTenant.current_tenant_id.nil?
113
+ record_tenant = record.attribute_was(partition_key)
114
+ if MultiTenant.current_tenant_id.nil? && !record_tenant.nil?
106
115
  MultiTenant.with(record.public_send(partition_key)) { block.call }
107
116
  else
108
117
  block.call
@@ -123,6 +132,20 @@ end
123
132
 
124
133
  ActiveSupport.on_load(:active_record) do |base|
125
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
126
149
  end
127
150
 
128
151
  class ActiveRecord::Associations::Association
@@ -1,6 +1,10 @@
1
- require 'request_store'
1
+ require 'active_support/current_attributes'
2
2
 
3
3
  module MultiTenant
4
+ class Current < ::ActiveSupport::CurrentAttributes
5
+ attribute :tenant
6
+ end
7
+
4
8
  def self.tenant_klass_defined?(tenant_name)
5
9
  !!tenant_name.to_s.classify.safe_constantize
6
10
  end
@@ -24,13 +28,23 @@ module MultiTenant
24
28
  def self.with_lock_workaround_enabled?; @@enable_with_lock_workaround; end
25
29
 
26
30
  # Registry that maps table names to models (used by the query rewriter)
27
- def self.register_multi_tenant_model(table_name, model_klass)
28
- @@multi_tenant_models ||= {}
29
- @@multi_tenant_models[table_name.to_s] = model_klass
31
+ def self.register_multi_tenant_model(model_klass)
32
+ @@multi_tenant_models ||= []
33
+ @@multi_tenant_models.push(model_klass)
34
+
35
+ remove_class_variable(:@@multi_tenant_model_table_names) if defined?(@@multi_tenant_model_table_names)
30
36
  end
37
+
31
38
  def self.multi_tenant_model_for_table(table_name)
32
- @@multi_tenant_models ||= {}
33
- @@multi_tenant_models[table_name.to_s]
39
+ @@multi_tenant_models ||= []
40
+
41
+ if !defined?(@@multi_tenant_model_table_names)
42
+ @@multi_tenant_model_table_names = @@multi_tenant_models.map { |model|
43
+ [model.table_name, model] if model.table_name
44
+ }.compact.to_h
45
+ end
46
+
47
+ @@multi_tenant_model_table_names[table_name.to_s]
34
48
  end
35
49
 
36
50
  def self.multi_tenant_model_for_arel(arel)
@@ -43,11 +57,11 @@ module MultiTenant
43
57
  end
44
58
 
45
59
  def self.current_tenant=(tenant)
46
- RequestStore.store[:current_tenant] = tenant
60
+ Current.tenant = tenant
47
61
  end
48
62
 
49
63
  def self.current_tenant
50
- RequestStore.store[:current_tenant]
64
+ Current.tenant
51
65
  end
52
66
 
53
67
  def self.current_tenant_id
@@ -95,6 +109,41 @@ module MultiTenant
95
109
  end
96
110
  end
97
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
+
98
147
  # Preserve backward compatibility for people using .with_id
99
148
  singleton_class.send(:alias_method, :with_id, :with)
100
149
 
@@ -295,12 +295,9 @@ module ActiveRecord
295
295
  end
296
296
 
297
297
  node_list.select{ |n| n.is_a? Arel::Nodes::Join }.each do |node_join|
298
- if (!node_join.right ||
299
- (ActiveRecord::VERSION::MAJOR == 5 &&
300
- !node_join.right.expr.right.is_a?(Arel::Attributes::Attribute)))
298
+ if !node_join.right
301
299
  next
302
300
  end
303
-
304
301
  relation_right, relation_left = relations_from_node_join(node_join)
305
302
 
306
303
  next unless relation_right && relation_left
@@ -308,7 +305,7 @@ module ActiveRecord
308
305
  model_right = MultiTenant.multi_tenant_model_for_table(relation_left.table_name)
309
306
  model_left = MultiTenant.multi_tenant_model_for_table(relation_right.table_name)
310
307
  if model_right && model_left
311
- join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(relation_left[model_left.partition_key], relation_right)
308
+ join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(relation_right[model_right.partition_key], relation_left)
312
309
  node_join.right.expr = node_join.right.expr.and(join_enforcement_clause)
313
310
  end
314
311
  end
@@ -322,19 +319,20 @@ module ActiveRecord
322
319
 
323
320
  private
324
321
  def relations_from_node_join(node_join)
325
- if ActiveRecord::VERSION::MAJOR == 5 || node_join.right.expr.is_a?(Arel::Nodes::Equality)
322
+ if node_join.right.expr.is_a?(Arel::Nodes::Equality)
326
323
  return node_join.right.expr.right.relation, node_join.right.expr.left.relation
327
324
  end
328
325
 
329
- children = node_join.right.expr.children
326
+ children = [node_join.right.expr.children].flatten
330
327
 
331
- tenant_applied = children.any?(MultiTenant::TenantEnforcementClause) || children.any?(MultiTenant::TenantJoinEnforcementClause)
328
+ tenant_applied = children.any?{|c| c.is_a?(MultiTenant::TenantEnforcementClause) || c.is_a?(MultiTenant::TenantJoinEnforcementClause)}
332
329
  if tenant_applied || children.empty?
333
330
  return nil, nil
334
331
  end
335
332
 
336
- if children[0].right.respond_to?('relation') && children[0].left.respond_to?('relation')
337
- return children[0].right.relation, children[0].left.relation
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
338
336
  end
339
337
 
340
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)
@@ -1,3 +1,3 @@
1
1
  module MultiTenant
2
- VERSION = '1.2.0'
2
+ VERSION = '2.2.0'
3
3
  end
@@ -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,65 @@ 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
+
91
+ describe 'Changes table_name after multi_tenant called' do
92
+ before do
93
+ account_klass.has_many(:posts, anonymous_class: post_klass)
94
+ post_klass.belongs_to(:account, anonymous_class: account_klass)
95
+
96
+ @account1 = account_klass.create! name: 'foo'
97
+ @account2 = account_klass.create! name: 'bar'
98
+
99
+ @post1 = @account1.posts.create! name: 'foobar'
100
+ @post2 = @account2.posts.create! name: 'baz'
101
+
102
+ MultiTenant.current_tenant = @account1
103
+ @posts = post_klass.all
104
+ end
105
+
106
+ let(:account_klass) do
107
+ Class.new(Account) do
108
+ def self.name
109
+ 'Account'
110
+ end
111
+ end
112
+ end
113
+
114
+ let(:post_klass) do
115
+ Class.new(ActiveRecord::Base) do
116
+ self.table_name = 'unknown'
117
+
118
+ multi_tenant(:account)
119
+
120
+ self.table_name = 'posts'
121
+
122
+ def self.name
123
+ 'Post'
124
+ end
125
+ end
126
+ end
127
+
128
+ it { expect(@posts.length).to eq(1) }
129
+ it { expect(@posts).to eq([@post1]) }
130
+ end
131
+
73
132
  # Scoping models
74
133
  describe 'Project.all should be scoped to the current tenant if set' do
75
134
  before do
@@ -144,6 +203,22 @@ describe MultiTenant do
144
203
  end
145
204
  end
146
205
 
206
+ it 'handles belongs_to with optional: true' do
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
211
+
212
+ it 'handles changing tenant from nil to a value' do
213
+ record = OptionalSubTask.create(sub_task_id: sub_task.id)
214
+ expect(record.reload.sub_task).to eq(sub_task)
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)
220
+ end
221
+
147
222
  it 'handles has_many through' do
148
223
  MultiTenant.with(account) do
149
224
  expect(project.sub_tasks).to eq [sub_task]
@@ -234,6 +309,55 @@ describe MultiTenant do
234
309
  end
235
310
  end
236
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
+
237
361
  # ::with
238
362
  describe "::with" do
239
363
  it "should set current_tenant to the specified tenant inside the block" do
@@ -349,10 +473,10 @@ describe MultiTenant do
349
473
 
350
474
  it "applies the team_id conditions in the where clause" do
351
475
  option1 = <<-sql.strip
352
- SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "tasks"."project_id" = 1 AND "sub_tasks"."account_id" = 1 AND "tasks"."account_id" = 1
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
353
477
  sql
354
478
  option2 = <<-sql.strip
355
- SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "sub_tasks"."account_id" = 1 AND "tasks"."project_id" = 1 AND "tasks"."account_id" = 1
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
356
480
  sql
357
481
 
358
482
  account1 = Account.create! name: 'Account 1'
@@ -367,7 +491,7 @@ describe MultiTenant do
367
491
 
368
492
  MultiTenant.without do
369
493
  expected_sql = <<-sql
370
- SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "tasks"."project_id" = 1
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
371
495
  sql
372
496
 
373
497
  project = Project.first
@@ -405,7 +529,7 @@ describe MultiTenant do
405
529
  expect(project.categories).to include(category1)
406
530
 
407
531
  expected_sql = <<-sql
408
- SELECT "projects".* FROM "projects" INNER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "project_categories"."account_id" = "projects"."account_id" INNER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" WHERE "projects"."account_id" = 1
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
409
533
  sql
410
534
 
411
535
  expect(Project.where(account_id: 1).joins(:categories).to_sql).to eq(expected_sql.strip)
@@ -439,7 +563,7 @@ describe MultiTenant do
439
563
 
440
564
  MultiTenant.without do
441
565
  expected_sql = <<-sql
442
- 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 "project_categories"."account_id" = "projects"."account_id" LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" WHERE "projects"."account_id" = 1
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
443
567
  sql
444
568
 
445
569
  expect(Project.where(account_id: 1).eager_load(:categories).to_sql).to eq(expected_sql.strip)
@@ -471,7 +595,7 @@ describe MultiTenant do
471
595
 
472
596
  MultiTenant.without do
473
597
  expected_sql = <<-sql
474
- SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "projects"."account_id" = "tasks"."account_id" LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
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
475
599
  sql
476
600
 
477
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
@@ -34,6 +34,13 @@ ARGV.grep(/\w+_spec\.rb/).empty? && ActiveRecord::Schema.define(version: 1) do
34
34
  t.column :type, :string
35
35
  end
36
36
 
37
+ create_table :optional_sub_tasks, force: true do |t|
38
+ t.references :account, :integer
39
+ t.column :sub_task_id, :integer
40
+ t.column :name, :string
41
+ t.column :type, :string
42
+ end
43
+
37
44
  create_table :countries, force: true do |t|
38
45
  t.column :name, :string
39
46
  end
@@ -106,6 +113,11 @@ ARGV.grep(/\w+_spec\.rb/).empty? && ActiveRecord::Schema.define(version: 1) do
106
113
  t.column :domain_id, :integer
107
114
  end
108
115
 
116
+ create_table :posts, force: true, partition_key: :account_id do |t|
117
+ t.column :account_id, :integer
118
+ t.column :name, :string
119
+ end
120
+
109
121
  create_distributed_table :accounts, :id
110
122
  create_distributed_table :projects, :account_id
111
123
  create_distributed_table :managers, :account_id
@@ -121,6 +133,7 @@ ARGV.grep(/\w+_spec\.rb/).empty? && ActiveRecord::Schema.define(version: 1) do
121
133
  create_distributed_table :allowed_places, :account_id
122
134
  create_distributed_table :domains, :account_id
123
135
  create_distributed_table :pages, :account_id
136
+ create_distributed_table :posts, :account_id
124
137
  create_reference_table :categories
125
138
  end
126
139
 
@@ -128,6 +141,7 @@ class Account < ActiveRecord::Base
128
141
  multi_tenant :account
129
142
  has_many :projects
130
143
  has_one :manager, inverse_of: :account
144
+ has_many :optional_sub_tasks
131
145
  end
132
146
 
133
147
  class Project < ActiveRecord::Base
@@ -159,6 +173,14 @@ class SubTask < ActiveRecord::Base
159
173
  multi_tenant :account
160
174
  belongs_to :task
161
175
  has_one :project, through: :task
176
+ has_many :optional_sub_tasks
177
+ end
178
+
179
+ with_belongs_to_required_by_default do
180
+ class OptionalSubTask < ActiveRecord::Base
181
+ multi_tenant :account, optional: true
182
+ belongs_to :sub_task
183
+ end
162
184
  end
163
185
 
164
186
  class StiSubTask < SubTask
@@ -198,6 +220,7 @@ class Comment < ActiveRecord::Base
198
220
  end
199
221
 
200
222
  class Organization < ActiveRecord::Base
223
+ multi_tenant :organization
201
224
  has_many :uuid_records
202
225
  end
203
226
 
data/spec/spec_helper.rb CHANGED
@@ -46,4 +46,11 @@ def uses_prepared_statements?
46
46
  ActiveRecord::Base.connection.prepared_statements
47
47
  end
48
48
 
49
+ def with_belongs_to_required_by_default(&block)
50
+ default_value = ActiveRecord::Base.belongs_to_required_by_default
51
+ ActiveRecord::Base.belongs_to_required_by_default = true
52
+ yield
53
+ ensure
54
+ ActiveRecord::Base.belongs_to_required_by_default = default_value
55
+ end
49
56
  require 'schema'
metadata CHANGED
@@ -1,43 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-multi-tenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
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-04-11 00:00:00.000000000 Z
11
+ date: 2022-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: request_store
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.0.5
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: 1.0.5
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rails
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - ">="
32
18
  - !ruby/object:Gem::Version
33
- version: '4.2'
19
+ version: '6'
34
20
  type: :runtime
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
24
  - - ">="
39
25
  - !ruby/object:Gem::Version
40
- version: '4.2'
26
+ version: '6'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rspec
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -168,11 +154,9 @@ files:
168
154
  - activerecord-multi-tenant.gemspec
169
155
  - docker-compose.yml
170
156
  - gemfiles/.bundle/config
171
- - gemfiles/active_record_5.2.gemfile
172
157
  - gemfiles/active_record_6.0.gemfile
173
158
  - gemfiles/active_record_6.1.gemfile
174
159
  - gemfiles/active_record_7.0.gemfile
175
- - gemfiles/rails_5.2.gemfile
176
160
  - gemfiles/rails_6.0.gemfile
177
161
  - gemfiles/rails_6.1.gemfile
178
162
  - gemfiles/rails_7.0.gemfile
@@ -184,12 +168,12 @@ files:
184
168
  - lib/activerecord-multi-tenant/migrations.rb
185
169
  - lib/activerecord-multi-tenant/model_extensions.rb
186
170
  - lib/activerecord-multi-tenant/multi_tenant.rb
187
- - lib/activerecord-multi-tenant/persistence_extension.rb
188
171
  - lib/activerecord-multi-tenant/query_monitor.rb
189
172
  - lib/activerecord-multi-tenant/query_rewriter.rb
190
173
  - lib/activerecord-multi-tenant/sidekiq.rb
191
174
  - lib/activerecord-multi-tenant/version.rb
192
175
  - lib/activerecord-multi-tenant/with_lock.rb
176
+ - spec/activerecord-multi-tenant/associations_spec.rb
193
177
  - spec/activerecord-multi-tenant/controller_extensions_spec.rb
194
178
  - spec/activerecord-multi-tenant/fast_truncate_spec.rb
195
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 "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: "../"
@@ -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