Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v 1.2 - Newly created schema not copying public (parent) schema data type length #626

Closed
joemsak opened this issue Jan 9, 2020 · 3 comments

Comments

@joemsak
Copy link

joemsak commented Jan 9, 2020

Steps to reproduce

Using Apartment 1.2 on existing postgresql database
Have a model with a simple t.string :name column no other modifiers
Run Apartment::Tenant.create("schema_name")
Inspect ActiveRecord::Base.connection.columns("public.table_name")
=> name's sql_type is "character varying(255)"
Inspect ActiveRecord::Base.connection.columns("schema_name.table_name")

Expected behavior

=> name's sql_type is "character varying(255)"

Actual behavior

=> name's sql_type is "character varying"

System configuration

Rails 4.2
Ruby 2.3.8
Apartment 1.2

There is an INHERIT migration running which throws DatatypeMismatch error due to the new child schema's table not picking up the (255) character limit for the type

  • Database: (Tell us what database and its version you use.)

Postgresql 9.6 on AWS RDS

  • Apartment version:

1.2

  • Apartment config (in config/initializers/apartment.rb or so):
# frozen_string_literal: true

# Require whichever elevator you're using below here...
#
# require 'apartment/elevators/generic'
# require 'apartment/elevators/domain'
# require 'apartment/elevators/subdomain'
require 'apartment' unless Kannu.tenant.config.no_database?
require 'apartment/elevators/host_hash'
require 'apartment/adapters/postgresql_schema_from_sql_adapter'
#
# Apartment Configuration
#
if Kadenze.kannu? && !Kadenze.config.no_database?
  Apartment.configure do |config|
    # These models will not be multi-tenanted,
    # but remain in the global (public) namespace
    #
    # An example might be a Customer or Tenant model that stores each tenant information
    # ex:
    #
    # config.excluded_models = %w{Tenant}
    #
    config.excluded_models = %w[
      User
      Identity
      Instructor
      Student
      Institution
      Role
      EmailPreference
      UsersRole
      Membership
      Translation
      AfterParty::TaskRecord
      ConfirmationToken
      StripeConnectState
    ]

    # use postgres schemas?
    config.use_schemas = true

    # use raw SQL dumps for creating postgres schemas? (only appies with use_schemas set to true)
    config.use_sql = true

    # configure persistent schemas (E.g. hstore )
    # config.persistent_schemas = %w{ hstore }

    # add the Rails environment to database names?
    # config.prepend_environment = true
    # config.append_environment = true

    # supply list of database names for migrations to run on
    config.tenant_names = -> { Institution.pluck(:tenant_name) }
  end
end

##
# Elevator Configuration
# NOTE: This is specified in the application config to keep all of our middleware declarations in one place

# Rails.application.config.middleware.use 'Apartment::Elevators::Generic', lambda { |request|
#   # TODO: supply generic implementation
# }

# Rails.application.config.middleware.use 'Apartment::Elevators::Domain'

# Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'
  • use_schemas: (true or false)

  • Rails (or ActiveRecord) version:
    4.2

  • Ruby version:

2.3.8

I'm sure maybe I changed something, but I dont have a clue what, because the last tenant I created was fine, and now all newly created tenants are having this problem

@joemsak
Copy link
Author

joemsak commented Jan 9, 2020

@joemsak
Copy link
Author

joemsak commented Jan 9, 2020

Rooting around the commit history of the apartment initializer, I realized we've also had this laying around

# frozen_string_literal: true

require 'apartment/adapters/postgresql_adapter'

# Monkey patching Apartment to fix this:
# https://github.com/influitive/apartment/issues/532
module Apartment
  module Adapters
    class PostgresqlSchemaFromSqlAdapter < PostgresqlSchemaAdapter
      PSQL_DUMP_BLACKLISTED_STATEMENTS = [
        /SET search_path/i,                           # overridden later
        /SET lock_timeout/i,                          # new in postgresql 9.3
        /SET row_security/i,                          # new in postgresql 9.5
        /SET idle_in_transaction_session_timeout/i,   # new in postgresql 9.6
        /CREATE SCHEMA public/i                       # this schema already exists
      ].freeze

      def import_database_schema
        preserving_search_path do
          clone_pg_schema
          copy_schema_migrations
        end
      end

      def clone_pg_schema
        pg_schema_sql = patch_search_path(pg_dump_schema)
        Apartment.connection.execute(pg_schema_sql)
      end

      def preserving_search_path
        search_path = Apartment.connection.execute('show search_path').first['search_path']
        yield
        Apartment.connection.execute("set search_path = #{search_path}")
      end

      def patch_search_path(sql)
        search_path = "SET search_path = \"#{current}\", #{default_tenant};"

        swap_schema_qualifier(sql)
          .split("\n")
          .select { |line| check_input_against_regexps(line, PSQL_DUMP_BLACKLISTED_STATEMENTS).empty? }
          .prepend(search_path)
          .join("\n")
      end

      def swap_schema_qualifier(sql)
        sql.gsub(/#{default_tenant}\.\w*/) do |match|
          match.gsub(default_tenant, %("#{current}"))
        end
      end
    end
  end
  end

This has been here seemingly not causing issues for a year or so, and I don't know what it's really doing or is for, I haven't messed with it

@joemsak
Copy link
Author

joemsak commented Jan 10, 2020

This one turned out to be totally my fault. Red herrings threw me off. It was a loading order dependency in my initializers. I was referencing Apartment::Tenant in some custom domain code before all other initializers, meaning the adapter would load and memoize with the default config options, and the apartment config initializer would not take over and set the PostgresqlSchemaFromSqlAdapter - once I fixed the ordering, and that adapter is set, the tenant inherits worked.

@joemsak joemsak closed this as completed Jan 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant