diff --git a/README.md b/README.md index fa033c09..4ffc9231 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,16 @@ switched back at the end of the block to what it was before. There is also `switch!` which doesn't take a block, but it's recommended to use `switch`. To return to the default tenant, you can call `switch` with no arguments. +#### Multiple Tenants + +When using schemas, you can also pass in a list of schemas if desired. Any tables defined in a schema earlier in the chain will be referenced first, so this is only useful if you have a schema with only some of the tables defined: + +```ruby +Apartment::Tenant.switch(['tenant_1', 'tenant_2']) do + # ... +end +``` + ### Switching Tenants per request You can have Apartment route to the appropriate tenant by adding some Rack middleware. diff --git a/lib/apartment/adapters/jdbc_postgresql_adapter.rb b/lib/apartment/adapters/jdbc_postgresql_adapter.rb index 70dbadf3..3e9494b0 100644 --- a/lib/apartment/adapters/jdbc_postgresql_adapter.rb +++ b/lib/apartment/adapters/jdbc_postgresql_adapter.rb @@ -38,11 +38,9 @@ class JDBCPostgresqlSchemaAdapter < PostgresqlSchemaAdapter # def connect_to_new(tenant = nil) return reset if tenant.nil? + raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless schema_exists?(tenant) - tenant = tenant.to_s - raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless tenant_exists?(tenant) - - @current = tenant + @current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s Apartment.connection.schema_search_path = full_search_path rescue ActiveRecord::StatementInvalid, ActiveRecord::JDBCError raise TenantNotFound, "One of the following schema(s) is invalid: #{full_search_path}" diff --git a/lib/apartment/adapters/postgresql_adapter.rb b/lib/apartment/adapters/postgresql_adapter.rb index 9540f016..32fbbe1e 100644 --- a/lib/apartment/adapters/postgresql_adapter.rb +++ b/lib/apartment/adapters/postgresql_adapter.rb @@ -72,11 +72,9 @@ def drop_command(conn, tenant) # def connect_to_new(tenant = nil) return reset if tenant.nil? + raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless schema_exists?(tenant) - tenant = tenant.to_s - raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless tenant_exists?(tenant) - - @current = tenant + @current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s Apartment.connection.schema_search_path = full_search_path # When the PostgreSQL version is < 9.3, @@ -149,6 +147,12 @@ def reset_sequence_names 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 + + [*schemas].all? { |schema| Apartment.connection.schema_exists?(schema.to_s) } + end end # Another Adapter for Postgresql when using schemas and SQL diff --git a/spec/examples/schema_adapter_examples.rb b/spec/examples/schema_adapter_examples.rb index 447322e3..f8c98ac7 100644 --- a/spec/examples/schema_adapter_examples.rb +++ b/spec/examples/schema_adapter_examples.rb @@ -127,6 +127,13 @@ 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 + subject.switch([schema1, schema2]) do + expect(connection.schema_search_path).to include %{"#{schema1}"} + expect(connection.schema_search_path).to include %{"#{schema2}"} + end + end end describe '#reset' do