Skip to content

Commit

Permalink
Support rails 7.2 (#239)
Browse files Browse the repository at this point in the history
* Add rails 7.2 to Appraisals

* The key of _reflections is a symbol since Rails 7.2.

related: rails/rails#51726

`_reflect_on_association` is also a private API and will may be broken, but it works
for both String and Symbol, absorbing type differences, so use this one.

* cached_find_by_statement requires two positional arguments in Rails 7.2.

related: rails/rails#51725

* build_arel requires `connection` as arguments in Rails 7.2.

related: rails/rails#51725

* Introduced #attributes_for_inspect in Rails 7.2

By default, only `id` is output, so set `:all` to output all attributes for testing.
related: rails/rails#49765

* Overrides #reset_primary_key to modify @primary_key.

ar-multitenant expects that #primary_key returns single column instead of composite primary_keys for backward compatibilities.

Previously overwriting #primary_key to return single pk, but since the timing for
writing @primary_key has changed since Rails 7.2, this way is no longer available.
Instead, overwriting `#reset_primary_key`, which handles calculating `@primary_key`.

* fix rubocop

related: #239 (comment)
  • Loading branch information
alpaca-tc authored Aug 23, 2024
1 parent 28487fb commit 0ac43aa
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/active-record-multi-tenant-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,18 @@ jobs:
- '3.0'
- '3.1'
- '3.2'
- '3.3'
appraisal:
- rails-6.0
- rails-6.1
- rails-7.0
- rails-7.1
- rails-7.2
- active-record-6.0
- active-record-6.1
- active-record-7.0
- active-record-7.1
- active-record-7.2
citus_version:
- '10'
- '11'
Expand Down
8 changes: 8 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ appraise 'rails-7.1' do
gem 'rails', '~> 7.1.0'
end

appraise 'rails-7.2' do
gem 'rails', '~> 7.2.0'
end

appraise 'active-record-6.0' do
gem 'activerecord', '~> 6.0.3'
end
Expand All @@ -31,3 +35,7 @@ end
appraise 'active-record-7.1' do
gem 'activerecord', '~> 7.1.0'
end

appraise 'active-record-7.2' do
gem 'activerecord', '~> 7.2.0'
end
2 changes: 1 addition & 1 deletion lib/activerecord-multi-tenant/habtm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def has_and_belongs_to_many_with_tenant(name, scope = nil, **options, &extension
# rubocop:enable Naming/PredicateName
has_and_belongs_to_many_without_tenant(name, scope, **options, &extension)

middle_reflection = _reflections[name.to_s].through_reflection
middle_reflection = _reflect_on_association(name.to_s).through_reflection
join_model = middle_reflection.klass

# get tenant_enabled from options and if it is not set, set it to false
Expand Down
19 changes: 7 additions & 12 deletions lib/activerecord-multi-tenant/model_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,15 @@ def partition_key
.try(:instance_variable_get, :@partition_key)
end

# Avoid primary_key errors when using composite primary keys (e.g. id, tenant_id)
def primary_key
if defined?(PRIMARY_KEY_NOT_SET) ? !PRIMARY_KEY_NOT_SET.equal?(@primary_key) : @primary_key
return @primary_key
end

def reset_primary_key
primary_object_keys = Array.wrap(connection.schema_cache.primary_keys(table_name)) - [partition_key]

@primary_key = if primary_object_keys.size == 1
primary_object_keys.first
elsif table_name &&
connection.schema_cache.columns_hash(table_name).include?(DEFAULT_ID_FIELD)
DEFAULT_ID_FIELD
end
self.primary_key = if primary_object_keys.size == 1
primary_object_keys.first
elsif table_name &&
connection.schema_cache.columns_hash(table_name).include?(DEFAULT_ID_FIELD)
DEFAULT_ID_FIELD
end
end

def inherited(subclass)
Expand Down
15 changes: 11 additions & 4 deletions lib/activerecord-multi-tenant/query_rewriter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,18 @@ def relations_from_node_join(node_join)
ActiveRecord::QueryMethods.prepend(MultiTenant::QueryMethodsExtensions)

module MultiTenantFindBy
def cached_find_by_statement(key, &block)
return super unless respond_to?(:scoped_by_tenant?) && scoped_by_tenant?
if ActiveRecord::VERSION::MAJOR >= 7 && ActiveRecord::VERSION::MINOR >= 2
def cached_find_by_statement(connection, key, &block)
return super unless respond_to?(:scoped_by_tenant?) && scoped_by_tenant?

key = Array.wrap(key) + [MultiTenant.current_tenant_id.to_s]
super
super(connection, Array.wrap(key) + [MultiTenant.current_tenant_id.to_s], &block)
end
else
def cached_find_by_statement(key, &block)
return super unless respond_to?(:scoped_by_tenant?) && scoped_by_tenant?

super(Array.wrap(key) + [MultiTenant.current_tenant_id.to_s], &block)
end
end
end

Expand Down
9 changes: 8 additions & 1 deletion lib/activerecord-multi-tenant/relation_extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ def generate_in_condition_subquery
tenant_id = MultiTenant.current_tenant_id

# Build an Arel query
arel = eager_loading? ? apply_join_dependency.arel : build_arel
arel = if eager_loading?
apply_join_dependency.arel
elsif ActiveRecord::VERSION::MAJOR >= 7 && ActiveRecord::VERSION::MINOR >= 2
build_arel(klass.connection)
else
build_arel
end

arel.source.left = table

# If the tenant ID is present and the tenant key is a column in the model,
Expand Down
11 changes: 11 additions & 0 deletions spec/activerecord-multi-tenant/model_extensions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ def self.name
end

describe 'inspect method filters senstive column values' do
if ActiveRecord::VERSION::MAJOR >= 7 && ActiveRecord::VERSION::MINOR >= 2
# related: https://github.com/rails/rails/pull/49765
around do |example|
prev = Account.attributes_for_inspect
Account.attributes_for_inspect = :all
example.run
ensure
Account.attributes_for_inspect = prev
end
end

it 'filters senstive value' do
account = Account.new(name: 'foo', password: 'baz')
expect(account.inspect).to eq '#<Account id: nil, name: nil, subdomain: nil, domain: nil, password: [FILTERED]>'
Expand Down

0 comments on commit 0ac43aa

Please sign in to comment.