Rails Postgres Schema Issue - One of the following schema(s) is invalid: "test" "public"

4k Views Asked by At

I've searched high and low for an answer to this but I'm coming up short.

I'm trying to build a multi-tenant application with Rails 4, Devise, and Apartment based on Postgres schemas. For my local Postgres server I decided to use PostgresApp. I followed the Go Rails multi-tenant guide and I had that setup (one user per tenant) working when this error started to appear. This started showing locally yesterday while I was trying to install the Invitable extension for Devise and I can't seem to find any clues as to what is going on.

Here is how I get the specific error:

michael$ rake environment db:drop
michael$ rake db:create
michael$ rake db:migrate
== 20160908204559 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0091s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0032s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0031s
-- add_index(:users, :confirmation_token, {:unique=>true})
   -> 0.0032s
-- add_index(:users, :unlock_token, {:unique=>true})
   -> 0.0029s
== 20160908204559 DeviseCreateUsers: migrated (0.0219s) =======================

    [WARNING] - The list of tenants to migrate appears to be empty. This could mean a few things:

      1. You may not have created any, in which case you can ignore this message
      2. You've run `apartment:migrate` directly without loading the Rails environment
        * `apartment:migrate` is now deprecated. Tenants will automatically be migrated with `db:migrate`

    Note that your tenants currently haven't been migrated. You'll need to run `db:migrate` to rectify this.
michael$ rake db:seed
Seeding test tenant
One of the following schema(s) is invalid: "test" "public"

When visiting the site locally, this results in Rails throwing:

Apartment::TenantNotFound

One of the following schema(s) is invalid: "www" "public"

Here is my apartment.rb initializer:

require 'apartment/elevators/subdomain'
Apartment.configure do |config|
  config.excluded_models = %w{ User }
  config.tenant_names = lambda { User.pluck :subdomain }
  config.use_schemas = true
end
Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'

Here is my Users migration file:

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      t.string   :unlock_token # Only if unlock strategy is :email or :both
      t.datetime :locked_at

      ## Invitable
      #t.string   :invitation_token
      #t.datetime :invitation_created_at
      #t.datetime :invitation_sent_at
      #t.datetime :invitation_accepted_at
      #t.integer  :invitation_limit
      #t.integer  :invited_by_id
      #t.string   :invited_by_type

      ## User Info
      t.string :first_name
      t.string :last_name
      t.string :subdomain
      t.string :role

      t.timestamps
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    add_index :users, :unlock_token,         unique: true
    #add_index :users, :invitation_token,     unique: true
  end
end

I've also gone into the local Postrgres database by command line. The drop is working, the create database is working. I can provide these if needed. My guess at the moment is telling me that there is something wrong with how Rails is talking to PostgresApp or how I'm doing migrations. But maybe someone with more experience can point something out that I've missed.

So my questions are what am I doing to cause this? How can I fix it? And how can I learn more about what is wrong?

3

There are 3 best solutions below

0
On BEST ANSWER

Okay, so I finally fixed it. There seems to have been a discrepancy between schemas when I migrated. For some reason, the schema was not being updated for some reason or another. I'm not entirely sure why this solved the issue, but what I did was go into the tenant class file and migration file (User.rb in my case) and then comment out everything except the bare minimum required for Devise. Then I ran one at a time:

rake db:drop
rake db:create 
rake db:migrate

On the migrate, I got an error:

duplicate key value violates unique constraint "index_users_on_email"

So then I went back and uncommented everything and re-ran the rakes and included rake db:seed this time. And it worked!

michael$ rake db:seed
Seeding test tenant
michael$ 

My best guess as to why this error was being thrown was either that:

  1. The old database schema was somehow persisting between drops
  2. That the new schema.rb file was not being updated and there was a discrepancy somehow

Either way, it seems like this was perfect storm scenario. I'll post back if I can recreate it. If this happens to someone else focus solely on the schema and not the database, apartment, or devise. That should save you a lot of time. I hope this helps someone else.

0
On

Apartment is looking for a subdomain: www.site.com. So you have to excluded from the list of available name for subdomain.

Apartment::TenantNotFound

One of the following schema(s) is invalid: "www" "public"

you need to add to the initializers/apartment

Apartment::Elevators::Subdomain.excluded_subdomains = ['www']

a bonus if you want main domain routers

routers.rb

This will constraints the routes urls for the main www.site.com or site.com

class RootDomain
  @subdomains = ["www"]
  def self.matches?(request)
   @subdomains.include?(request.subdomain) || request.subdomain.blank?
  end
end

constraints(RootDomain) do
  your resources for the main domain only. 
end
0
On

I had a similar error. My problem was I had an existing app which I was trying to implement the Apartment Gem on.

I solved this error by creating each schema retrospectively in my rails console e.g.

Company.all.each do |c| 
  Apartment::Tenant.create(c.subdomain)
end

NOTE make sure subdomains are lower e.g. 'testsubdomain'