influitive / apartment

Database multi-tenancy for Rack (and Rails) applications
2.68k stars 460 forks source link

There was an exception - Apartment::TenantNotFound(One of the following schema(s) is invalid: "" "public") #530

Open nynhex opened 6 years ago

nynhex commented 6 years ago

I'm working on an app for my company with Rails 5.1.5, Ruby 2.5.0, and Apartment latest gem cut 2.1

I haven't worked on this app for 6 months. And even before I upgraded to 5.1.5/2.5.0 I was on Rails 5.0.1 and Ruby 2.4.0 and received this error. just stalled the project and never got around to revisiting it.

There was an exception - Apartment::TenantNotFound(One of the following schema(s) is invalid: "" "public")

I'm using Postgres, for what it's worth.

I've dropped the database, recreated it, ran the migrations which did not error out. Yet when I start the rails server I get the following exception/stacktrace:

There was an exception - Apartment::TenantNotFound(One of the following schema(s) is invalid: "" "public")
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/apartment-2.1.0/lib/apartment/adapters/postgresql_adapter.rb:79:in `rescue in connect_to_new'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/apartment-2.1.0/lib/apartment/adapters/postgresql_adapter.rb:64:in `connect_to_new'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/apartment-2.1.0/lib/apartment/adapters/abstract_adapter.rb:71:in `block in switch!'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:97:in `run_callbacks'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/apartment-2.1.0/lib/apartment/adapters/abstract_adapter.rb:68:in `switch!'
/Users/nynhex/Dropbox/alterramd/app/channels/application_cable/connection.rb:7:in `connect'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/connection/base.rb:167:in `handle_open'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker.rb:58:in `block in invoke'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker.rb:39:in `block in work'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:108:in `block in run_callbacks'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker/active_record_connection_management.rb:14:in `block in with_database_connections'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/connection/tagged_logger_proxy.rb:22:in `block in tag'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:69:in `block in tagged'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:26:in `tagged'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:69:in `tagged'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/connection/tagged_logger_proxy.rb:22:in `tag'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker/active_record_connection_management.rb:14:in `with_database_connections'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/engine.rb:60:in `block (4 levels) in <class:Engine>'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/execution_wrapper.rb:85:in `wrap'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/engine.rb:55:in `block (3 levels) in <class:Engine>'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `instance_exec'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:135:in `run_callbacks'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker.rb:38:in `work'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker.rb:56:in `invoke'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/actioncable-5.1.5/lib/action_cable/server/worker.rb:51:in `block in async_invoke'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:348:in `run_task'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:337:in `block (3 levels) in create_worker'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:320:in `loop'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:320:in `block (2 levels) in create_worker'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:319:in `catch'
/Users/nynhex/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:319:in `block in create_worker'

Any help you can provide is greatly appreciated.

mikecmpbll commented 6 years ago

how're you switching?

nynhex commented 6 years ago

In the application controller, in a before_action like so:

before_action :load_schema, :authenticate_user!

  private

    def load_schema
      Apartment::Tenant.switch!('public')
      return unless request.subdomain.present?

      if current_account
        Apartment::Tenant.switch!(current_account.subdomain)
      else
        redirect_to root_url(subdomain: false)
      end
    end

Note, this worked before, but perhaps I don't have a public schema in postgres? This is a new machine.

mikecmpbll commented 6 years ago

looks like 'tenant', here https://github.com/influitive/apartment/blob/development/lib/apartment/adapters/postgresql_adapter.rb#L79, is an empty string, judging from the error message.

could current_account.subdomain be returning an empty string? debug along those lines and you should be able to get to the bottom of it.

nynhex commented 6 years ago

@mikecmpbll Thanks for the dig on this Mike. I'll take a look at it today. I just bootstrapped the app on my laptop a while back so right now there's no account objects or anything seeded. But IIRC when I was working on this in the past I didn't require an account to be there. It just switched to the public schema. I'll post my findings hopefully today so we can close this out. 👍

niteshp commented 6 years ago

@nynhex / @mikecmpbll were you able to figure this out ? I'm running into the same error while deploying to AWS using Elastic Beanstalk. In the browser, I receive the "We're sorry, but something went wrong." page ... but looking at the logs, I see this error: Apartment::TenantNotFound (One of the following schema(s) is invalid: "ata-prod" "public", "shared_extensions")

I'm stuck on this issue and any help would be appreciated ...

amielouwho commented 5 years ago

I am also running into this problem - anyone figure out the issue?

jayvarner commented 5 years ago

I ran into to this today after I mucked around with a few things in my environment. I could switch in the console, but not via http requests. By chance, I ran db:migrate and saw that some of the tenants were missing migrations in their "schema_migrations" table. However, the tenants did have the tables referenced in the migrations. So real dirty, in the console I did the following (note: TourSet is my class for tenants):

schemas = ActiveRecord::SchemaMigration.all
TourSet.all.each do |ts|
Apartment::Tenant.switch!(ts.subdir)
schemas.each do |schema|
  migration = ActiveRecord::SchemaMigration.find_by_version(schema.version)
  if migration.nil?
      ActiveRecord::SchemaMigration.create(version: schema.version)
    end
  end
end

I'm not proud, but it worked for me. Maybe some of y'all have similar issues. ¯_(ツ)_/¯

tim-lynn-clark commented 5 years ago

I am having the same, if not a similar issue. All migrations run against the 'public' schema without issues, so to do the seeds (using seed_fu). But, when Apartment tries to create the schemas for each of the tenants I get the following error.

rake db:migrate

Migrating zenith tenant One of the following schema(s) is invalid: "zenith" "public" Migrating myotherapy tenant One of the following schema(s) is invalid: "myotherapy" "public"

I have tried running migrate against PGv11, PGv10, and PGv9 and I get the same error.

Gem Versions: Ruby 2.6.1 Rails 5.2.2 pg 1.1.4 or 0.21.0 (tried both) apartment 2.2.0

Apartment Config: Subdomain config.excluded_models = %w{ Clinic } config.tenant_names = ['zenith', 'myotherapy'] (everything else left at defaults)

Application Config: Subdomain config.middleware.use Apartment::Elevators::Subdomain

promisepreston commented 5 years ago

I ran into the same issue, and here's how I fixed it

I simply added an after_create callback called create_tenant to the model of the subdomain for my multi-tenant, which is user.rb in app/models/user.rb

Find below a link on Stackoverflow for the detailed answer https://stackoverflow.com/a/57771338/10907864

Angelo-Igitego commented 3 years ago

I had the same issue and I solved it by:

  1. logging into Postgres CLI: sudo -u postgres psql
  2. then connecting to the right database: \c databasename; (to view all existing databases, run: \l+)
  3. viewing all existing schemas: \dn+;
  4. After realizing that the schema in question was wrongly named (it had an extra underscore, while the name of the tenant didn't have it), I altered the schema as necessary: ALTER SCHEMA old_name RENAME TO new_name

After this, everything got back to normal.