activerecord-multi-tenant 2.3.0 → 2.4.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: ba7796208980393ca21739d24fa0ac384f0c63ab814041cf46e0216d22eef539
4
- data.tar.gz: 107cea123278629ce9492b15eb6e168549eac4c155fe9a906e57e1695414faf7
3
+ metadata.gz: f277cdbd6175c03dcbbca13e06220f5612fdf40cefb539a3619b4afa0077d369
4
+ data.tar.gz: bae03db825cc60a9833a2287245b7ff5f62ede9aa67497594e867832a75eaedf
5
5
  SHA512:
6
- metadata.gz: c184c2db6316a82d4b092dfdaff1cb69cde80319837302822b7fe8ae387bf627fa6e8670f828d980636e448761e51629c38c53d42dbb505d094f1a2b5eba4b54
7
- data.tar.gz: c021571f18b6072a98bbe0793607077b785a3a989e3365cd45cd7c0d94fb89f5ed30f3129b35199d88aeab653d6c656d20028a84a5ce74bedbaf2a3c6d36c5b6
6
+ metadata.gz: fad6c663f7f588e1359ea4f831b1c66d24de31fa9895aee3ac42d59851597b3ceabf2576c4e2eb49f55baef6eaeb787fee946085b43909450580d4b6a66817cb
7
+ data.tar.gz: c58700fda6a8e99b928435f2bd5abfdc62eb6ccb249ab21350d12f25d9b6ff29860d12451e5e8a77aa2666302d8a9dbfa9bc062dab450ecfdfce2226452c0d43
@@ -51,13 +51,16 @@ jobs:
51
51
  - rails-6.0
52
52
  - rails-6.1
53
53
  - rails-7.0
54
+ - rails-7.1
54
55
  - active-record-6.0
55
56
  - active-record-6.1
56
57
  - active-record-7.0
58
+ - active-record-7.1
57
59
  citus_version:
58
60
  - '10'
59
61
  - '11'
60
-
62
+ - '12'
63
+
61
64
  name: Ruby ${{ matrix.ruby }}/${{ matrix.gemfile }} / Citus ${{ matrix.citus_version }}
62
65
  env:
63
66
  APPRAISAL: ${{ matrix.appraisal }}
data/Appraisals CHANGED
@@ -10,6 +10,10 @@ appraise 'rails-7.0' do
10
10
  gem 'rails', '~> 7.0.0'
11
11
  end
12
12
 
13
+ appraise 'rails-7.1' do
14
+ gem 'rails', '~> 7.1.0.beta1'
15
+ end
16
+
13
17
  appraise 'active-record-6.0' do
14
18
  gem 'activerecord', '~> 6.0.3'
15
19
  end
@@ -21,3 +25,7 @@ end
21
25
  appraise 'active-record-7.0' do
22
26
  gem 'activerecord', '~> 7.0.0'
23
27
  end
28
+
29
+ appraise 'active-record-7.1' do
30
+ gem 'activerecord', '~> 7.1.0.beta1'
31
+ end
data/CHANGELOG.md CHANGED
@@ -1,4 +1,11 @@
1
1
  # Changelog
2
+
3
+ ## 2.4.0 2023-06-05
4
+ * Adds citus 12 to test matrix (#210)
5
+ * Adds Support for rails 7.1 (#208)
6
+ * Fix missing scope in habtm.rb (#207)
7
+ * Update logic inside the tenant_klass_defined? method (#202)
8
+
2
9
  ## 2.3.0 2023-06-05
3
10
  * Adds has_and_belongs_to_many feature with tenant (#193)
4
11
  * Removes eol ruby versions
@@ -8,7 +8,7 @@ alabaster==0.7.13
8
8
  # via sphinx
9
9
  babel==2.12.1
10
10
  # via sphinx
11
- certifi==2023.5.7
11
+ certifi==2023.7.22
12
12
  # via requests
13
13
  charset-normalizer==3.1.0
14
14
  # via requests
@@ -8,9 +8,9 @@ module ActiveRecord
8
8
  module Associations
9
9
  module ClassMethods
10
10
  # rubocop:disable Naming/PredicateName
11
- def has_and_belongs_to_many_with_tenant(name, options = {}, &extension)
11
+ def has_and_belongs_to_many_with_tenant(name, scope = nil, **options, &extension)
12
12
  # rubocop:enable Naming/PredicateName
13
- has_and_belongs_to_many_without_tenant(name, **options, &extension)
13
+ has_and_belongs_to_many_without_tenant(name, scope, **options, &extension)
14
14
 
15
15
  middle_reflection = _reflections[name.to_s].through_reflection
16
16
  join_model = middle_reflection.klass
@@ -67,7 +67,7 @@ module MultiTenant
67
67
  partition_key = @partition_key
68
68
 
69
69
  # Create an implicit belongs_to association only if tenant class exists
70
- if MultiTenant.tenant_klass_defined?(tenant_name)
70
+ if MultiTenant.tenant_klass_defined?(tenant_name, options)
71
71
  belongs_to tenant_name, **options.slice(:class_name, :inverse_of, :optional)
72
72
  .merge(foreign_key: options[:partition_key])
73
73
  end
@@ -103,7 +103,7 @@ module MultiTenant
103
103
  tenant_id
104
104
  end
105
105
 
106
- if MultiTenant.tenant_klass_defined?(tenant_name)
106
+ if MultiTenant.tenant_klass_defined?(tenant_name, options)
107
107
  define_method "#{tenant_name}=" do |model|
108
108
  super(model)
109
109
  if send("#{partition_key}_changed?") && persisted? && !send("#{partition_key}_was").nil?
@@ -5,8 +5,13 @@ module MultiTenant
5
5
  attribute :tenant
6
6
  end
7
7
 
8
- def self.tenant_klass_defined?(tenant_name)
9
- !!tenant_name.to_s.classify.safe_constantize
8
+ def self.tenant_klass_defined?(tenant_name, options = {})
9
+ class_name = if options[:class_name].present?
10
+ options[:class_name]
11
+ else
12
+ tenant_name.to_s.classify
13
+ end
14
+ !!class_name.safe_constantize
10
15
  end
11
16
 
12
17
  def self.partition_key(tenant_name)
@@ -58,9 +63,9 @@ module MultiTenant
58
63
  return nil unless arel.respond_to?(:ast)
59
64
 
60
65
  if arel.ast.relation.is_a? Arel::Nodes::JoinSource
61
- MultiTenant.multi_tenant_model_for_table(arel.ast.relation.left.table_name)
66
+ MultiTenant.multi_tenant_model_for_table(TableNode.table_name(arel.ast.relation.left))
62
67
  else
63
- MultiTenant.multi_tenant_model_for_table(arel.ast.relation.table_name)
68
+ MultiTenant.multi_tenant_model_for_table(TableNode.table_name(arel.ast.relation))
64
69
  end
65
70
  end
66
71
 
@@ -83,7 +83,7 @@ module MultiTenant
83
83
 
84
84
  def visit_Arel_Nodes_Equality(obj, *args)
85
85
  if obj.left.is_a?(Arel::Attributes::Attribute)
86
- table_name = obj.left.relation.table_name
86
+ table_name = MultiTenant::TableNode.table_name(obj.left.relation)
87
87
  model = MultiTenant.multi_tenant_model_for_table(table_name)
88
88
  if model.present? && obj.left.name.to_s == model.partition_key.to_s
89
89
  @current_context.visited_handled_relation(obj.left.relation)
@@ -101,7 +101,7 @@ module MultiTenant
101
101
  end
102
102
 
103
103
  def visit_Arel_Table(obj, _collector = nil)
104
- @current_context.visited_relation(obj) if tenant_relation?(obj.table_name)
104
+ @current_context.visited_relation(obj) if tenant_relation?(MultiTenant::TableNode.table_name(obj))
105
105
  end
106
106
 
107
107
  alias visit_Arel_Nodes_TableAlias visit_Arel_Table
@@ -179,7 +179,9 @@ module MultiTenant
179
179
  def initialize(tenant_attribute)
180
180
  super()
181
181
  @tenant_attribute = tenant_attribute
182
- @tenant_model = MultiTenant.multi_tenant_model_for_table(tenant_attribute.relation.table_name)
182
+ @tenant_model = MultiTenant.multi_tenant_model_for_table(
183
+ MultiTenant::TableNode.table_name(tenant_attribute.relation)
184
+ )
183
185
  end
184
186
 
185
187
  def to_s
@@ -215,7 +217,7 @@ module MultiTenant
215
217
  def initialize(tenant_attribute, table_left)
216
218
  super(tenant_attribute)
217
219
  @table_left = table_left
218
- @model_left = MultiTenant.multi_tenant_model_for_table(table_left.table_name)
220
+ @model_left = MultiTenant.multi_tenant_model_for_table(MultiTenant::TableNode.table_name(table_left))
219
221
  end
220
222
 
221
223
  private
@@ -241,7 +243,7 @@ module MultiTenant
241
243
  module DatabaseStatements
242
244
  def join_to_update(update, *args)
243
245
  update = super(update, *args)
244
- model = MultiTenant.multi_tenant_model_for_table(update.ast.relation.table_name)
246
+ model = MultiTenant.multi_tenant_model_for_table(MultiTenant::TableNode.table_name(update.ast.relation))
245
247
  if model.present? && !MultiTenant.with_write_only_mode_enabled? && MultiTenant.current_tenant_id.present?
246
248
  update.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
247
249
  end
@@ -250,7 +252,7 @@ module MultiTenant
250
252
 
251
253
  def join_to_delete(delete, *args)
252
254
  delete = super(delete, *args)
253
- model = MultiTenant.multi_tenant_model_for_table(delete.ast.left.table_name)
255
+ model = MultiTenant.multi_tenant_model_for_table(MultiTenant::TableNode.table_name(delete.ast.left))
254
256
  if model.present? && !MultiTenant.with_write_only_mode_enabled? && MultiTenant.current_tenant_id.present?
255
257
  delete.where(MultiTenant::TenantEnforcementClause.new(model.arel_table[model.partition_key]))
256
258
  end
@@ -295,7 +297,7 @@ module ActiveRecord
295
297
  node = context.arel_node
296
298
 
297
299
  context.unhandled_relations.each do |relation|
298
- model = MultiTenant.multi_tenant_model_for_table(relation.arel_table.table_name)
300
+ model = MultiTenant.multi_tenant_model_for_table(MultiTenant::TableNode.table_name(relation.arel_table))
299
301
 
300
302
  if MultiTenant.current_tenant_id
301
303
  enforcement_clause = MultiTenant::TenantEnforcementClause.new(relation.arel_table[model.partition_key])
@@ -330,8 +332,8 @@ module ActiveRecord
330
332
 
331
333
  next unless relation_right && relation_left
332
334
 
333
- model_right = MultiTenant.multi_tenant_model_for_table(relation_left.table_name)
334
- model_left = MultiTenant.multi_tenant_model_for_table(relation_right.table_name)
335
+ model_right = MultiTenant.multi_tenant_model_for_table(MultiTenant::TableNode.table_name(relation_left))
336
+ model_left = MultiTenant.multi_tenant_model_for_table(MultiTenant::TableNode.table_name(relation_right))
335
337
  next unless model_right && model_left
336
338
 
337
339
  join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(
@@ -0,0 +1,13 @@
1
+ module MultiTenant
2
+ module TableNode
3
+ # Return table name
4
+ def self.table_name(node)
5
+ # NOTE: Arel::Nodes::Table#table_name is removed in Rails 7.1
6
+ if node.is_a?(Arel::Nodes::TableAlias)
7
+ node.table_name
8
+ else
9
+ node.name
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module MultiTenant
2
- VERSION = '2.3.0'.freeze
2
+ VERSION = '2.4.0'.freeze
3
3
  end
@@ -8,5 +8,6 @@ require_relative 'activerecord-multi-tenant/model_extensions'
8
8
  require_relative 'activerecord-multi-tenant/multi_tenant'
9
9
  require_relative 'activerecord-multi-tenant/query_rewriter'
10
10
  require_relative 'activerecord-multi-tenant/query_monitor'
11
+ require_relative 'activerecord-multi-tenant/table_node'
11
12
  require_relative 'activerecord-multi-tenant/version'
12
13
  require_relative 'activerecord-multi-tenant/habtm'
@@ -64,4 +64,58 @@ RSpec.describe MultiTenant do
64
64
  end
65
65
  end
66
66
  end
67
+
68
+ describe '.tenant_klass_defined?' do
69
+ context 'without options' do
70
+ before(:all) do
71
+ class SampleTenant < ActiveRecord::Base
72
+ multi_tenant :sample_tenant
73
+ end
74
+ end
75
+
76
+ it 'return true with valid tenant_name' do
77
+ expect(MultiTenant.tenant_klass_defined?(:sample_tenant)).to eq(true)
78
+ end
79
+
80
+ it 'return false with invalid_tenant_name' do
81
+ invalid_tenant_name = :tenant
82
+ expect(MultiTenant.tenant_klass_defined?(invalid_tenant_name)).to eq(false)
83
+ end
84
+ end
85
+
86
+ context 'with options' do
87
+ context 'and valid class_name' do
88
+ it 'return true' do
89
+ class SampleTenant < ActiveRecord::Base
90
+ multi_tenant :tenant
91
+ end
92
+
93
+ tenant_name = :tenant
94
+ options = {
95
+ class_name: 'SampleTenant'
96
+ }
97
+ expect(MultiTenant.tenant_klass_defined?(tenant_name, options)).to eq(true)
98
+ end
99
+
100
+ it 'return true when tenant class is nested' do
101
+ module SampleModule
102
+ class SampleNestedTenant < ActiveRecord::Base
103
+ multi_tenant :tenant
104
+ end
105
+ # rubocop:disable Layout/TrailingWhitespace
106
+ # Trailing whitespace is intentionally left here
107
+
108
+ class AnotherTenant < ActiveRecord::Base
109
+ end
110
+ # rubocop:enable Layout/TrailingWhitespace
111
+ end
112
+ tenant_name = :tenant
113
+ options = {
114
+ class_name: 'SampleModule::SampleNestedTenant'
115
+ }
116
+ expect(MultiTenant.tenant_klass_defined?(tenant_name, options)).to eq(true)
117
+ end
118
+ end
119
+ end
120
+ end
67
121
  end
data/spec/schema.rb CHANGED
@@ -174,8 +174,8 @@ end
174
174
  class Manager < ActiveRecord::Base
175
175
  multi_tenant :account
176
176
  belongs_to :project
177
- has_and_belongs_to_many :tasks, { tenant_column: :account_id, tenant_enabled: true,
178
- tenant_class_name: 'Account' }
177
+ has_and_belongs_to_many :tasks, tenant_column: :account_id, tenant_enabled: true,
178
+ tenant_class_name: 'Account'
179
179
  end
180
180
 
181
181
  class Task < ActiveRecord::Base
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.3.0
4
+ version: 2.4.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: 2023-06-06 00:00:00.000000000 Z
11
+ date: 2023-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -276,6 +276,7 @@ files:
276
276
  - lib/activerecord-multi-tenant/query_monitor.rb
277
277
  - lib/activerecord-multi-tenant/query_rewriter.rb
278
278
  - lib/activerecord-multi-tenant/sidekiq.rb
279
+ - lib/activerecord-multi-tenant/table_node.rb
279
280
  - lib/activerecord-multi-tenant/version.rb
280
281
  - lib/activerecord_multi_tenant.rb
281
282
  - spec/activerecord-multi-tenant/associations_spec.rb