From ff02612240c4ae05479e341075855225dc6e7a1c Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Tue, 14 Sep 2021 22:38:00 +0800 Subject: [PATCH 01/20] [#151] removed reloader and console overwrite of reload method --- .rubocop_todo.yml | 6 ------ lib/apartment/console.rb | 16 ---------------- lib/apartment/railtie.rb | 19 ------------------- lib/apartment/reloader.rb | 22 ---------------------- spec/unit/reloader_spec.rb | 24 ------------------------ 5 files changed, 87 deletions(-) delete mode 100644 lib/apartment/reloader.rb delete mode 100644 spec/unit/reloader_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 3650e125..ce2bf148 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -77,7 +77,6 @@ RSpec/DescribedClass: - 'spec/tenant_spec.rb' - 'spec/unit/elevators/host_hash_spec.rb' - 'spec/unit/migrator_spec.rb' - - 'spec/unit/reloader_spec.rb' # Offense count: 5 # Cop supports --auto-correct. @@ -128,7 +127,6 @@ RSpec/FilePath: - 'spec/unit/elevators/host_spec.rb' - 'spec/unit/elevators/subdomain_spec.rb' - 'spec/unit/migrator_spec.rb' - - 'spec/unit/reloader_spec.rb' # Offense count: 1 # Cop supports --auto-correct. @@ -159,7 +157,6 @@ RSpec/InstanceVariable: # Cop supports --auto-correct. RSpec/LeadingSubject: Exclude: - - 'spec/unit/reloader_spec.rb' # Offense count: 2 RSpec/LeakyConstantDeclaration: @@ -196,7 +193,6 @@ RSpec/NamedSubject: - 'spec/support/contexts.rb' - 'spec/support/requirements.rb' - 'spec/tenant_spec.rb' - - 'spec/unit/reloader_spec.rb' # Offense count: 24 RSpec/NestedGroups: @@ -217,7 +213,6 @@ RSpec/VerifiedDoubles: Exclude: - 'spec/integration/apartment_rake_integration_spec.rb' - 'spec/unit/elevators/first_subdomain_spec.rb' - - 'spec/unit/reloader_spec.rb' # Offense count: 17 Style/Documentation: @@ -233,7 +228,6 @@ Style/Documentation: - 'lib/apartment/migrator.rb' - 'lib/apartment/model.rb' - 'lib/apartment/railtie.rb' - - 'lib/apartment/reloader.rb' - 'lib/apartment/tasks/enhancements.rb' - 'lib/apartment/tasks/task_helper.rb' - 'lib/generators/apartment/install/install_generator.rb' diff --git a/lib/apartment/console.rb b/lib/apartment/console.rb index 91721222..6cc3900d 100644 --- a/lib/apartment/console.rb +++ b/lib/apartment/console.rb @@ -1,21 +1,5 @@ # frozen_string_literal: true -# A workaround to get `reload!` to also call Apartment::Tenant.init -# This is unfortunate, but I haven't figured out how to hook into the reload process *after* files are reloaded - -# reloads the environment -# rubocop:disable Style/OptionalBooleanParameter -def reload!(print = true) - puts 'Reloading...' if print - - # This triggers the to_prepare callbacks - ActionDispatch::Callbacks.new(proc {}).call({}) - # Manually init Apartment again once classes are reloaded - Apartment::Tenant.init - true -end -# rubocop:enable Style/OptionalBooleanParameter - def st(schema_name = nil) if schema_name.nil? tenant_list.each { |t| puts t } diff --git a/lib/apartment/railtie.rb b/lib/apartment/railtie.rb index ba4e5728..efbe9c48 100644 --- a/lib/apartment/railtie.rb +++ b/lib/apartment/railtie.rb @@ -2,7 +2,6 @@ require 'rails' require 'apartment/tenant' -require 'apartment/reloader' module Apartment class Railtie < Rails::Railtie @@ -60,23 +59,5 @@ class Railtie < Rails::Railtie load 'tasks/apartment.rake' require 'apartment/tasks/enhancements' if Apartment.db_migrate_tenants end - - # - # The following initializers are a workaround to the fact that I can't properly hook into the rails reloader - # Note this is technically valid for any environment where cache_classes is false, for us, it's just development - # - if Rails.env.development? - - # Apartment::Reloader is middleware to initialize things properly on each request to dev - initializer 'apartment.init' do |app| - app.config.middleware.use Apartment::Reloader - end - - # Overrides reload! to also call Apartment::Tenant.init as well - # so that the reloaded classes have the proper table_names - console do - require 'apartment/console' - end - end end end diff --git a/lib/apartment/reloader.rb b/lib/apartment/reloader.rb deleted file mode 100644 index cd8b6861..00000000 --- a/lib/apartment/reloader.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module Apartment - class Reloader - # Middleware used in development to init Apartment for each request - # Necessary due to code reload (annoying). When models are reloaded, they no longer have the proper table_name - # That is prepended with the schema (if using postgresql schemas) - # I couldn't figure out how to properly hook into the Rails reload process *after* files are reloaded - # so I've used this in the meantime. - # - # Also see apartment/console for the re-definition of reload! that re-init's Apartment - # - def initialize(app) - @app = app - end - - def call(env) - Tenant.init - @app.call(env) - end - end -end diff --git a/spec/unit/reloader_spec.rb b/spec/unit/reloader_spec.rb deleted file mode 100644 index b194a46c..00000000 --- a/spec/unit/reloader_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Apartment::Reloader do - context 'when using postgresql schemas' do - before do - Apartment.configure do |config| - config.excluded_models = ['Company'] - config.use_schemas = true - end - Apartment::Tenant.reload!(config) - Company.reset_table_name # ensure we're clean - end - - subject { Apartment::Reloader.new(double('Rack::Application', call: nil)) } - - it 'initializes apartment when called' do - expect(Company.table_name).not_to include('public.') - subject.call(double('env')) - expect(Company.table_name).to include('public.') - end - end -end From 51831288ba1a37b1f27f01c08d7fb9f5e106ccc1 Mon Sep 17 00:00:00 2001 From: Pedro Nascimento Date: Tue, 19 Oct 2021 20:07:11 +0000 Subject: [PATCH 02/20] Show previous error message --- lib/apartment/adapters/postgresql_adapter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index 5d7f9e21..e1b8474a 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -82,8 +82,8 @@ def connect_to_new(tenant = nil) # https://www.postgresql.org/docs/9.3/static/sql-prepare.html Apartment.connection.clear_cache! if postgresql_version < 90_300 reset_sequence_names - rescue *rescuable_exceptions - raise TenantNotFound, "One of the following schema(s) is invalid: \"#{tenant}\" #{full_search_path}" + rescue *rescuable_exceptions => e + raise TenantNotFound, "One of the following schema(s) is invalid: \"#{tenant}\" #{full_search_path}.\nOriginal error: #{e.message}" end private From cbaed2185dbcd1eda2422dcba07d53ad2cbfaeb8 Mon Sep 17 00:00:00 2001 From: Pedro Nascimento Date: Fri, 22 Oct 2021 14:13:14 +0000 Subject: [PATCH 03/20] Show underlying error message and class if we cannot set search path to a new schema Relates to #166 --- lib/apartment/adapters/postgresql_adapter.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index e1b8474a..6e9707de 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -83,7 +83,7 @@ def connect_to_new(tenant = nil) Apartment.connection.clear_cache! if postgresql_version < 90_300 reset_sequence_names rescue *rescuable_exceptions => e - raise TenantNotFound, "One of the following schema(s) is invalid: \"#{tenant}\" #{full_search_path}.\nOriginal error: #{e.message}" + raise_schema_connect_to_new(tenant, e) end private @@ -153,6 +153,13 @@ def schema_exists?(schemas) Array(schemas).all? { |schema| Apartment.connection.schema_exists?(schema.to_s) } end + + def raise_schema_connect_to_new(tenant, exception) + raise TenantNotFound, <<~EXCEPTION_MESSAGE + Could not set search path to schemas, they may be invalid: "#{tenant}" #{full_search_path}. + Original error: #{exception.class}: #{exception} + EXCEPTION_MESSAGE + end end # Another Adapter for Postgresql when using schemas and SQL From 35b11fed5d666b1629a99fc4f712cc774460937f Mon Sep 17 00:00:00 2001 From: Stef Schenkelaars Date: Thu, 16 Dec 2021 10:48:14 +0100 Subject: [PATCH 04/20] Add rails 7 support The code didn't have to change to support it, it was just about making the gem requirements a bit more relaxed. To validate everything works as expected, rails 7 is added to the test matrix. Closes https://github.com/rails-on-services/apartment/issues/177 --- .circleci/config.yml | 4 +++- .ruby-version | 2 +- Appraisals | 36 ++++++++++++----------------------- gemfiles/rails_4_2.gemfile | 25 ------------------------ gemfiles/rails_5_0.gemfile | 23 ---------------------- gemfiles/rails_5_1.gemfile | 23 ---------------------- gemfiles/rails_5_2.gemfile | 6 ------ gemfiles/rails_6_0.gemfile | 6 ------ gemfiles/rails_6_1.gemfile | 6 ------ gemfiles/rails_7_0.gemfile | 17 +++++++++++++++++ gemfiles/rails_master.gemfile | 12 +++--------- ros-apartment.gemspec | 2 +- 12 files changed, 37 insertions(+), 125 deletions(-) delete mode 100644 gemfiles/rails_4_2.gemfile delete mode 100644 gemfiles/rails_5_0.gemfile delete mode 100644 gemfiles/rails_5_1.gemfile create mode 100644 gemfiles/rails_7_0.gemfile diff --git a/.circleci/config.yml b/.circleci/config.yml index 6ae44ff4..8572f1dc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,9 @@ workflows: matrix: parameters: ruby_version: ["ruby:2.6-buster", "ruby:2.7-buster", "ruby:3.0-buster"] - gemfile: ["gemfiles/rails_5_2.gemfile", "gemfiles/rails_6_0.gemfile", "gemfiles/rails_6_1.gemfile"] + gemfile: ["gemfiles/rails_5_2.gemfile", "gemfiles/rails_6_0.gemfile", "gemfiles/rails_6_1.gemfile", "gemfiles/rails_7_0.gemfile"] exclude: - ruby_version: "ruby:3.0-buster" gemfile: "gemfiles/rails_5_2.gemfile" + - ruby_version: "ruby:2.6-buster" + gemfile: "gemfiles/rails_7_0.gemfile" diff --git a/.ruby-version b/.ruby-version index 2c9b4ef4..a603bb50 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.3 +2.7.5 diff --git a/Appraisals b/Appraisals index 5f55c5ac..43e788a4 100644 --- a/Appraisals +++ b/Appraisals @@ -1,29 +1,5 @@ # frozen_string_literal: true -appraise 'rails-5-0' do - gem 'rails', '~> 5.0.0' - platforms :ruby do - gem 'pg', '< 1.0.0' - end - platforms :jruby do - gem 'activerecord-jdbc-adapter', '~> 50.0' - gem 'activerecord-jdbcpostgresql-adapter', '~> 50.0' - gem 'activerecord-jdbcmysql-adapter', '~> 50.0' - end -end - -appraise 'rails-5-1' do - gem 'rails', '~> 5.1.0' - platforms :ruby do - gem 'pg', '< 1.0.0' - end - platforms :jruby do - gem 'activerecord-jdbc-adapter', '~> 51.0' - gem 'activerecord-jdbcpostgresql-adapter', '~> 51.0' - gem 'activerecord-jdbcmysql-adapter', '~> 51.0' - end -end - appraise 'rails-5-2' do gem 'rails', '~> 5.2.0' platforms :jruby do @@ -57,6 +33,18 @@ appraise 'rails-6-1' do end end +appraise 'rails-7-0' do + gem 'rails', '~> 7.0.0' + platforms :ruby do + gem 'sqlite3', '~> 1.4' + end + platforms :jruby do + gem 'activerecord-jdbc-adapter', '~> 61.0' + gem 'activerecord-jdbcpostgresql-adapter', '~> 61.0' + gem 'activerecord-jdbcmysql-adapter', '~> 61.0' + end +end + appraise 'rails-master' do gem 'rails', git: 'https://github.com/rails/rails.git' platforms :ruby do diff --git a/gemfiles/rails_4_2.gemfile b/gemfiles/rails_4_2.gemfile deleted file mode 100644 index 33048072..00000000 --- a/gemfiles/rails_4_2.gemfile +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -# This file was generated by Appraisal - -source 'http://rubygems.org' - -gem 'rails', '~> 4.2.0' - -group :local do - gem 'guard-rspec', '~> 4.2' - gem 'pry' -end - -platforms :ruby do - gem 'mysql2', '~> 0.4.0' - gem 'pg', '< 1.0.0' -end - -platforms :jruby do - gem 'activerecord-jdbc-adapter', '~> 1.3' - gem 'activerecord-jdbcmysql-adapter', '~> 1.3' - gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3' -end - -gemspec path: '../' diff --git a/gemfiles/rails_5_0.gemfile b/gemfiles/rails_5_0.gemfile deleted file mode 100644 index 37dc042b..00000000 --- a/gemfiles/rails_5_0.gemfile +++ /dev/null @@ -1,23 +0,0 @@ -# This file was generated by Appraisal - -source "http://rubygems.org" - -gem "rails", "~> 5.0.0" -gem "rubocop" - -group :local do - gem "guard-rspec", "~> 4.2" - gem "pry" -end - -platforms :ruby do - gem "pg", "< 1.0.0" -end - -platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 50.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 50.0" - gem "activerecord-jdbcmysql-adapter", "~> 50.0" -end - -gemspec path: "../" diff --git a/gemfiles/rails_5_1.gemfile b/gemfiles/rails_5_1.gemfile deleted file mode 100644 index 59af05f8..00000000 --- a/gemfiles/rails_5_1.gemfile +++ /dev/null @@ -1,23 +0,0 @@ -# This file was generated by Appraisal - -source "http://rubygems.org" - -gem "rails", "~> 5.1.0" -gem "rubocop" - -group :local do - gem "guard-rspec", "~> 4.2" - gem "pry" -end - -platforms :ruby do - gem "pg", "< 1.0.0" -end - -platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 51.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 51.0" - gem "activerecord-jdbcmysql-adapter", "~> 51.0" -end - -gemspec path: "../" diff --git a/gemfiles/rails_5_2.gemfile b/gemfiles/rails_5_2.gemfile index 18d8952a..e50bd638 100644 --- a/gemfiles/rails_5_2.gemfile +++ b/gemfiles/rails_5_2.gemfile @@ -3,12 +3,6 @@ source "http://rubygems.org" gem "rails", "~> 5.2.0" -gem "rubocop" - -group :local do - gem "guard-rspec", "~> 4.2" - gem "pry" -end platforms :jruby do gem "activerecord-jdbc-adapter", "~> 52.0" diff --git a/gemfiles/rails_6_0.gemfile b/gemfiles/rails_6_0.gemfile index 6d23e4aa..64778099 100644 --- a/gemfiles/rails_6_0.gemfile +++ b/gemfiles/rails_6_0.gemfile @@ -3,12 +3,6 @@ source "http://rubygems.org" gem "rails", "~> 6.0.0" -gem "rubocop" - -group :local do - gem "guard-rspec", "~> 4.2" - gem "pry" -end platforms :ruby do gem "sqlite3", "~> 1.4" diff --git a/gemfiles/rails_6_1.gemfile b/gemfiles/rails_6_1.gemfile index e6de4f27..ef48f142 100644 --- a/gemfiles/rails_6_1.gemfile +++ b/gemfiles/rails_6_1.gemfile @@ -3,12 +3,6 @@ source "http://rubygems.org" gem "rails", "~> 6.1.0" -gem "rubocop" - -group :local do - gem "guard-rspec", "~> 4.2" - gem "pry" -end platforms :ruby do gem "sqlite3", "~> 1.4" diff --git a/gemfiles/rails_7_0.gemfile b/gemfiles/rails_7_0.gemfile new file mode 100644 index 00000000..52256985 --- /dev/null +++ b/gemfiles/rails_7_0.gemfile @@ -0,0 +1,17 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +gem "rails", "~> 7.0.0" + +platforms :ruby do + gem "sqlite3", "~> 1.4" +end + +platforms :jruby do + gem "activerecord-jdbc-adapter", "~> 61.0" + gem "activerecord-jdbcpostgresql-adapter", "~> 61.0" + gem "activerecord-jdbcmysql-adapter", "~> 61.0" +end + +gemspec path: "../" diff --git a/gemfiles/rails_master.gemfile b/gemfiles/rails_master.gemfile index 82ad9191..200ae4d1 100644 --- a/gemfiles/rails_master.gemfile +++ b/gemfiles/rails_master.gemfile @@ -3,21 +3,15 @@ source "http://rubygems.org" gem "rails", git: "https://github.com/rails/rails.git" -gem "rubocop" - -group :local do - gem "guard-rspec", "~> 4.2" - gem "pry" -end platforms :ruby do gem "sqlite3", "~> 1.4" end platforms :jruby do - gem "activerecord-jdbc-adapter", "~> 52.0" - gem "activerecord-jdbcpostgresql-adapter", "~> 52.0" - gem "activerecord-jdbcmysql-adapter", "~> 52.0" + gem "activerecord-jdbc-adapter", "~> 61.0" + gem "activerecord-jdbcpostgresql-adapter", "~> 61.0" + gem "activerecord-jdbcmysql-adapter", "~> 61.0" end gemspec path: "../" diff --git a/ros-apartment.gemspec b/ros-apartment.gemspec index 169865c4..1f513d52 100644 --- a/ros-apartment.gemspec +++ b/ros-apartment.gemspec @@ -27,7 +27,7 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/rails-on-services/apartment' s.licenses = ['MIT'] - s.add_dependency 'activerecord', '>= 5.0.0', '< 6.2' + s.add_dependency 'activerecord', '>= 5.0.0', '< 7.1' s.add_dependency 'parallel', '< 2.0' s.add_dependency 'public_suffix', '>= 2.0.5', '< 5.0' s.add_dependency 'rack', '>= 1.3.6', '< 3.0' From 6ec081358794b9680781877b6f2f39e8ce235973 Mon Sep 17 00:00:00 2001 From: Guillaume Briday <8252238+guillaumebriday@users.noreply.github.com> Date: Thu, 23 Dec 2021 17:20:54 +0100 Subject: [PATCH 05/20] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ffc9231..58ecd407 100644 --- a/README.md +++ b/README.md @@ -344,7 +344,7 @@ Setting this configuration value to `false` will disable the schema presence che ```ruby Apartment.configure do |config| - tenant_presence_check = false + config.tenant_presence_check = false end ``` From b580421ea37c83cf0332169961ef45ba4819b8a5 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Tue, 1 Feb 2022 17:45:47 +0100 Subject: [PATCH 06/20] copied fsateler solution from the draft pr to this https://github.com/rails-on-services/apartment/pull/143/files --- lib/apartment.rb | 1 + .../active_record/postgresql_adapter.rb | 18 +++++++++++++++++ lib/apartment/adapters/postgresql_adapter.rb | 20 ------------------- spec/examples/schema_adapter_examples.rb | 8 ++++++-- 4 files changed, 25 insertions(+), 22 deletions(-) create mode 100644 lib/apartment/active_record/postgresql_adapter.rb diff --git a/lib/apartment.rb b/lib/apartment.rb index 8a774b5b..a4aba389 100644 --- a/lib/apartment.rb +++ b/lib/apartment.rb @@ -8,6 +8,7 @@ require_relative 'apartment/log_subscriber' +require_relative 'apartment/active_record/postgresql_adapter' if ActiveRecord.version.release >= Gem::Version.new('6.0') require_relative 'apartment/active_record/connection_handling' end diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb new file mode 100644 index 00000000..bf963266 --- /dev/null +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Apartment::PostgreSqlAdapterPatch + def default_sequence_name(table, _column) + res = super + schema_prefix = "#{Apartment::Tenant.current}." + if res&.starts_with?(schema_prefix) && Apartment.excluded_models.none?{|m| m.constantize.table_name == table} + res.delete_prefix!(schema_prefix) + end + res + end +end + +require 'active_record/connection_adapters/postgresql_adapter' + +class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter + include Apartment::PostgreSqlAdapterPatch +end diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index 6e9707de..47584911 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -41,7 +41,6 @@ def default_tenant def reset @current = default_tenant Apartment.connection.schema_search_path = full_search_path - reset_sequence_names end def init @@ -81,7 +80,6 @@ def connect_to_new(tenant = nil) # there is a issue for prepared statement with changing search_path. # https://www.postgresql.org/docs/9.3/static/sql-prepare.html Apartment.connection.clear_cache! if postgresql_version < 90_300 - reset_sequence_names rescue *rescuable_exceptions => e raise_schema_connect_to_new(tenant, e) end @@ -130,24 +128,6 @@ def postgresql_version Apartment.connection.send(:postgresql_version) end - def reset_sequence_names - # sequence_name contains the schema, so it must be reset after switch - # There is `reset_sequence_name`, but that method actually goes to the database - # to find out the new name. Therefore, we do this hack to only unset the name, - # and it will be dynamically found the next time it is needed - descendants_to_unset = ActiveRecord::Base.descendants - .select { |c| c.instance_variable_defined?(:@sequence_name) } - .reject do |c| - c.instance_variable_defined?(:@explicit_sequence_name) && - c.instance_variable_get(:@explicit_sequence_name) - end - descendants_to_unset.each do |c| - # NOTE: due to this https://github.com/rails-on-services/apartment/issues/81 - # unreproduceable error we're checking before trying to remove it - c.remove_instance_variable :@sequence_name if c.instance_variable_defined?(:@sequence_name) - end - end - def schema_exists?(schemas) return true unless Apartment.tenant_presence_check diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index 586dce62..f4ce50fb 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -27,6 +27,9 @@ Apartment::Tenant.init expect(Company.table_name).to eq('public.companies') + expect(Company.sequence_name).to eq('public.companies_id_seq') + expect(User.table_name).to eq('users') + expect(User.sequence_name).to eq('users_id_seq') end context 'with a default_tenant', default_tenant: true do @@ -34,6 +37,9 @@ Apartment::Tenant.init expect(Company.table_name).to eq("#{default_tenant}.companies") + expect(Company.sequence_name).to eq("#{default_tenant}.companies_id_seq") + expect(User.table_name).to eq('users') + expect(User.sequence_name).to eq('users_id_seq') end it 'sets the search_path correctly' do @@ -119,11 +125,9 @@ it 'connects and resets' do subject.switch(schema1) do expect(connection.schema_search_path).to start_with %("#{schema1}") - expect(User.sequence_name).to eq "#{schema1}.#{User.table_name}_id_seq" end expect(connection.schema_search_path).to start_with %("#{public_schema}") - expect(User.sequence_name).to eq "#{public_schema}.#{User.table_name}_id_seq" end it 'allows a list of schemas' do From 226d112d8da191b7fc1cc7c0721a5d07f81f4694 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 12:18:04 +0100 Subject: [PATCH 07/20] added some tests --- lib/apartment/active_record/postgresql_adapter.rb | 9 ++++++++- spec/examples/schema_adapter_examples.rb | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb index bf963266..ea1f55d0 100644 --- a/lib/apartment/active_record/postgresql_adapter.rb +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -1,10 +1,15 @@ # frozen_string_literal: true +# rubocop:disable Style/ClassAndModuleChildren + +# NOTE: This patch is meant to remove any schema_prefix appart from the ones for +# excluded models. The schema_prefix would be resolved by apartment's setting +# of search path module Apartment::PostgreSqlAdapterPatch def default_sequence_name(table, _column) res = super schema_prefix = "#{Apartment::Tenant.current}." - if res&.starts_with?(schema_prefix) && Apartment.excluded_models.none?{|m| m.constantize.table_name == table} + if res&.starts_with?(schema_prefix) && Apartment.excluded_models.none? { |m| m.constantize.table_name == table } res.delete_prefix!(schema_prefix) end res @@ -13,6 +18,8 @@ def default_sequence_name(table, _column) require 'active_record/connection_adapters/postgresql_adapter' +# NOTE: inject this into postgresql adapters class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter include Apartment::PostgreSqlAdapterPatch end +# rubocop:enable Style/ClassAndModuleChildren diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index f4ce50fb..25535390 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -125,9 +125,13 @@ it 'connects and resets' do subject.switch(schema1) do expect(connection.schema_search_path).to start_with %("#{schema1}") + expect(User.sequence_name).to eq "#{schema1}.#{User.table_name}_id_seq" + expect(Company.sequence_name).to eq "#{public_schema}.#{Company.table_name}_id_seq" end expect(connection.schema_search_path).to start_with %("#{public_schema}") + expect(User.sequence_name).to eq "#{User.table_name}_id_seq" + expect(Company.sequence_name).to eq "#{public_schema}.#{Company.table_name}_id_seq" end it 'allows a list of schemas' do From f5100f0a7d6a95ab9248e5af55bfe253e795010f Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 14:11:31 +0100 Subject: [PATCH 08/20] if current seq name does not match current tenant, fix it --- lib/apartment/active_record/postgresql_adapter.rb | 9 +++++++-- spec/examples/schema_adapter_examples.rb | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb index ea1f55d0..16ceb9ef 100644 --- a/lib/apartment/active_record/postgresql_adapter.rb +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -9,9 +9,14 @@ module Apartment::PostgreSqlAdapterPatch def default_sequence_name(table, _column) res = super schema_prefix = "#{Apartment::Tenant.current}." - if res&.starts_with?(schema_prefix) && Apartment.excluded_models.none? { |m| m.constantize.table_name == table } - res.delete_prefix!(schema_prefix) + + unless res.starts_with?(schema_prefix) + schema, _seq_name = extract_schema_qualified_name(res) + res.sub!("#{schema}.", schema_prefix) end + + res.delete_prefix!(schema_prefix) if Apartment.excluded_models.none? { |m| m.constantize.table_name == table } + res end end diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index 25535390..f007435f 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -125,7 +125,7 @@ it 'connects and resets' do subject.switch(schema1) do expect(connection.schema_search_path).to start_with %("#{schema1}") - expect(User.sequence_name).to eq "#{schema1}.#{User.table_name}_id_seq" + expect(User.sequence_name).to eq "#{User.table_name}_id_seq" expect(Company.sequence_name).to eq "#{public_schema}.#{Company.table_name}_id_seq" end From e43272d25c7f9592d5472ff3d0f45660bbc5f55c Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 20:08:20 +0100 Subject: [PATCH 09/20] dont create two different addapters --- spec/adapters/postgresql_adapter_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/adapters/postgresql_adapter_spec.rb b/spec/adapters/postgresql_adapter_spec.rb index 7944c862..981440f6 100644 --- a/spec/adapters/postgresql_adapter_spec.rb +++ b/spec/adapters/postgresql_adapter_spec.rb @@ -6,7 +6,7 @@ describe Apartment::Adapters::PostgresqlAdapter, database: :postgresql do unless defined?(JRUBY_VERSION) - subject { Apartment::Tenant.postgresql_adapter config } + subject { Apartment::Tenant.adapter } it_behaves_like 'a generic apartment adapter callbacks' From d9a7ece686343e3076ef830fd5574aabcef39557 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 20:18:53 +0100 Subject: [PATCH 10/20] removed complex logic and fixed failed checks --- lib/apartment/active_record/postgresql_adapter.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb index 16ceb9ef..05cfa0df 100644 --- a/lib/apartment/active_record/postgresql_adapter.rb +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -10,13 +10,13 @@ def default_sequence_name(table, _column) res = super schema_prefix = "#{Apartment::Tenant.current}." - unless res.starts_with?(schema_prefix) - schema, _seq_name = extract_schema_qualified_name(res) - res.sub!("#{schema}.", schema_prefix) + if res&.starts_with?(schema_prefix) + if Apartment.excluded_models.none? { |m| m.constantize.table_name == table } + res.delete_prefix!(schema_prefix) + else + res.sub!(schema_prefix, "#{Apartment::Tenant.default_tenant}.") + end end - - res.delete_prefix!(schema_prefix) if Apartment.excluded_models.none? { |m| m.constantize.table_name == table } - res end end From eb379d68309d0c04b5c7e0daf6c448eee1815277 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 21:05:51 +0100 Subject: [PATCH 11/20] assure company is always part of the excluded models --- spec/examples/schema_adapter_examples.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index f007435f..1fe2efef 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -122,6 +122,12 @@ end describe '#switch' do + before do + Apartment.configure do |config| + config.excluded_models = ['Company'] + end + end + it 'connects and resets' do subject.switch(schema1) do expect(connection.schema_search_path).to start_with %("#{schema1}") From 12f81a419bf69b6ab2b3768de387eff7720dbb71 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 21:47:22 +0100 Subject: [PATCH 12/20] using adapter in subject --- spec/adapters/mysql2_adapter_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/adapters/mysql2_adapter_spec.rb b/spec/adapters/mysql2_adapter_spec.rb index fea994f4..6ff7c56c 100644 --- a/spec/adapters/mysql2_adapter_spec.rb +++ b/spec/adapters/mysql2_adapter_spec.rb @@ -6,7 +6,7 @@ describe Apartment::Adapters::Mysql2Adapter, database: :mysql do unless defined?(JRUBY_VERSION) - subject(:adapter) { Apartment::Tenant.mysql2_adapter config } + subject(:adapter) { Apartment::Tenant.adapter } def tenant_names ActiveRecord::Base.connection.execute('SELECT schema_name FROM information_schema.schemata').collect do |row| From 114f65b6ae00282ea1fe2d4b4d13784582e5c49f Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 21:53:32 +0100 Subject: [PATCH 13/20] using adapter for subject --- spec/adapters/jdbc_mysql_adapter_spec.rb | 2 +- spec/adapters/jdbc_postgresql_adapter_spec.rb | 2 +- spec/adapters/sqlite3_adapter_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/adapters/jdbc_mysql_adapter_spec.rb b/spec/adapters/jdbc_mysql_adapter_spec.rb index b757c96b..de9c3860 100644 --- a/spec/adapters/jdbc_mysql_adapter_spec.rb +++ b/spec/adapters/jdbc_mysql_adapter_spec.rb @@ -6,7 +6,7 @@ require 'apartment/adapters/jdbc_mysql_adapter' describe Apartment::Adapters::JDBCMysqlAdapter, database: :mysql do - subject { Apartment::Tenant.jdbc_mysql_adapter config.symbolize_keys } + subject(:adapter) { Apartment::Tenant.adapter } def tenant_names ActiveRecord::Base.connection.execute('SELECT schema_name FROM information_schema.schemata').collect do |row| diff --git a/spec/adapters/jdbc_postgresql_adapter_spec.rb b/spec/adapters/jdbc_postgresql_adapter_spec.rb index d1deabf3..4db0eb8b 100644 --- a/spec/adapters/jdbc_postgresql_adapter_spec.rb +++ b/spec/adapters/jdbc_postgresql_adapter_spec.rb @@ -6,7 +6,7 @@ require 'apartment/adapters/jdbc_postgresql_adapter' describe Apartment::Adapters::JDBCPostgresqlAdapter, database: :postgresql do - subject { Apartment::Tenant.jdbc_postgresql_adapter config.symbolize_keys } + subject(:adapter) { Apartment::Tenant.adapter } it_behaves_like 'a generic apartment adapter callbacks' diff --git a/spec/adapters/sqlite3_adapter_spec.rb b/spec/adapters/sqlite3_adapter_spec.rb index 1581a3e3..339cb38c 100644 --- a/spec/adapters/sqlite3_adapter_spec.rb +++ b/spec/adapters/sqlite3_adapter_spec.rb @@ -6,7 +6,7 @@ describe Apartment::Adapters::Sqlite3Adapter, database: :sqlite do unless defined?(JRUBY_VERSION) - subject { Apartment::Tenant.sqlite3_adapter config } + subject(:adapter) { Apartment::Tenant.adapter } it_behaves_like 'a generic apartment adapter callbacks' From 4cbcbaa8c95b1102167ac11296c3df21ab14108a Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 21:55:01 +0100 Subject: [PATCH 14/20] ignore rubocop inline --- spec/examples/schema_adapter_examples.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index 1fe2efef..70c71504 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -128,6 +128,7 @@ end end + # rubocop:disable RSpec/MultipleExpectations it 'connects and resets' do subject.switch(schema1) do expect(connection.schema_search_path).to start_with %("#{schema1}") @@ -139,6 +140,7 @@ expect(User.sequence_name).to eq "#{User.table_name}_id_seq" expect(Company.sequence_name).to eq "#{public_schema}.#{Company.table_name}_id_seq" end + # rubocop:enable RSpec/MultipleExpectations it 'allows a list of schemas' do subject.switch([schema1, schema2]) do From cd6c19949ac66a9f26b9088b3c99d79ccc113a39 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Wed, 2 Feb 2022 23:42:55 +0100 Subject: [PATCH 15/20] reverse negative evaluation and skipping sub if not needed --- lib/apartment/active_record/postgresql_adapter.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb index 05cfa0df..333ec2a6 100644 --- a/lib/apartment/active_record/postgresql_adapter.rb +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -11,14 +11,23 @@ def default_sequence_name(table, _column) schema_prefix = "#{Apartment::Tenant.current}." if res&.starts_with?(schema_prefix) - if Apartment.excluded_models.none? { |m| m.constantize.table_name == table } - res.delete_prefix!(schema_prefix) + default_tenant_prefix = "#{Apartment::Tenant.default_tenant}." + # NOTE: Excluded models should always access the sequence from the default + # tenant schema + if excluded_model?(table) && schema_prefix != default_tenant_prefix + res.sub!(schema_prefix, default_tenant_prefix) else - res.sub!(schema_prefix, "#{Apartment::Tenant.default_tenant}.") + res.delete_prefix!(schema_prefix) end end res end + + private + + def excluded_model?(table) + Apartment.excluded_models.any? { |m| m.constantize.table_name == table } + end end require 'active_record/connection_adapters/postgresql_adapter' From 56f63fd3d8648e1ba5fcfa49ab377b3161b61f24 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Thu, 3 Feb 2022 00:13:17 +0100 Subject: [PATCH 16/20] fix conditional sub --- lib/apartment/active_record/postgresql_adapter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb index 333ec2a6..c31fc4c3 100644 --- a/lib/apartment/active_record/postgresql_adapter.rb +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -14,8 +14,8 @@ def default_sequence_name(table, _column) default_tenant_prefix = "#{Apartment::Tenant.default_tenant}." # NOTE: Excluded models should always access the sequence from the default # tenant schema - if excluded_model?(table) && schema_prefix != default_tenant_prefix - res.sub!(schema_prefix, default_tenant_prefix) + if excluded_model?(table) + res.sub!(schema_prefix, default_tenant_prefix) if schema_prefix != default_tenant_prefix else res.delete_prefix!(schema_prefix) end From b67bc7a4da864c0522a8d5befec9f252197a7438 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Thu, 3 Feb 2022 01:11:42 +0100 Subject: [PATCH 17/20] only require apartment PostgreSQLAdapter if were using postgres --- lib/apartment.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/apartment.rb b/lib/apartment.rb index a4aba389..8bb50440 100644 --- a/lib/apartment.rb +++ b/lib/apartment.rb @@ -8,7 +8,10 @@ require_relative 'apartment/log_subscriber' -require_relative 'apartment/active_record/postgresql_adapter' +if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) + require_relative 'apartment/active_record/postgresql_adapter' +end + if ActiveRecord.version.release >= Gem::Version.new('6.0') require_relative 'apartment/active_record/connection_handling' end From 092215754ca11a3d0fcd2ef14e6c51b52327a106 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Thu, 3 Feb 2022 01:42:02 +0100 Subject: [PATCH 18/20] move require of postgresql adapter patch to postgresql adapter --- lib/apartment.rb | 4 ---- lib/apartment/adapters/postgresql_adapter.rb | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/apartment.rb b/lib/apartment.rb index 8bb50440..8a774b5b 100644 --- a/lib/apartment.rb +++ b/lib/apartment.rb @@ -8,10 +8,6 @@ require_relative 'apartment/log_subscriber' -if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) - require_relative 'apartment/active_record/postgresql_adapter' -end - if ActiveRecord.version.release >= Gem::Version.new('6.0') require_relative 'apartment/active_record/connection_handling' end diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index 47584911..7b85aa51 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'apartment/adapters/abstract_adapter' +require 'apartment/active_record/postgresql_adapter' module Apartment module Tenant From 19f1e17bb29768b510a3b6ec59df1400f69de465 Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Thu, 3 Feb 2022 01:50:17 +0100 Subject: [PATCH 19/20] cleanup default sequence name --- .../active_record/postgresql_adapter.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/apartment/active_record/postgresql_adapter.rb b/lib/apartment/active_record/postgresql_adapter.rb index c31fc4c3..ef878111 100644 --- a/lib/apartment/active_record/postgresql_adapter.rb +++ b/lib/apartment/active_record/postgresql_adapter.rb @@ -9,17 +9,17 @@ module Apartment::PostgreSqlAdapterPatch def default_sequence_name(table, _column) res = super schema_prefix = "#{Apartment::Tenant.current}." + default_tenant_prefix = "#{Apartment::Tenant.default_tenant}." - if res&.starts_with?(schema_prefix) - default_tenant_prefix = "#{Apartment::Tenant.default_tenant}." - # NOTE: Excluded models should always access the sequence from the default - # tenant schema - if excluded_model?(table) - res.sub!(schema_prefix, default_tenant_prefix) if schema_prefix != default_tenant_prefix - else - res.delete_prefix!(schema_prefix) - end + # NOTE: Excluded models should always access the sequence from the default + # tenant schema + if excluded_model?(table) + res.sub!(schema_prefix, default_tenant_prefix) if schema_prefix != default_tenant_prefix + return res end + + res.delete_prefix!(schema_prefix) if res&.starts_with?(schema_prefix) + res end From 2d034f0d28dd2da245f0b939291055b1328c9fcd Mon Sep 17 00:00:00 2001 From: Rui Baltazar Date: Mon, 7 Feb 2022 07:48:32 +0100 Subject: [PATCH 20/20] version bump --- lib/apartment/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/apartment/version.rb b/lib/apartment/version.rb index 31deaf81..4a24fa5e 100644 --- a/lib/apartment/version.rb +++ b/lib/apartment/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Apartment - VERSION = '2.10.0' + VERSION = '2.11.0' end