class Ekylibre::MultiTenancy::Middleware::ContainerAwareRackMiddleware

Provides a rack based tenant switching solution based on request

Attributes

excluded_subdomains[W]

Public Class Methods

excluded_subdomains() click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 15
def excluded_subdomains
  @excluded_subdomains ||= []
end
new(app) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 20
def initialize(app)
  @app = app
end

Public Instance Methods

call(env) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 24
def call(env)
  request = Rack::Request.new(env)
  container = env.fetch('container').dup

  PluginSystem::GlobalContainer.replace_with(container) do
    env['container'] = container

    database = extract_tenant(request)

    begin
      if database
        container
          .get(TenantSwitcher)
          .switch(database) { @app.call(env) }
      else
        @app.call(env)
      end
    rescue ::Apartment::TenantNotFound
      Rails.logger.error "Apartment Tenant not found: #{subdomain(request.host)}"
      return [404, { 'Content-Type' => 'text/html' }, [File.read(Rails.root.join('public', '404.html'))]]
    end
  end
end
extract_tenant(request) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 48
def extract_tenant(request)
  if (tenant = ENV['tenant'])
    tenant
  elsif ::Rails.env.test?
    'test'
  elsif ENV['ELEVATOR'] == 'header'
    request.env['HTTP_X_TENANT']
  else
    extract_subdomain(request)
  end
end

Private Instance Methods

domain_valid?(host) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 95
def domain_valid?(host)
  PublicSuffix.valid?(host, ignore_private: true)
end
extract_subdomain(request) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 62
def extract_subdomain(request)
  request_subdomain = subdomain(request.host)

  # If the domain acquired is set to be excluded, set the tenant to whatever is currently
  # next in line in the schema search path.
  tenant = if self.class.excluded_subdomains.include?(request_subdomain)
             nil
           else
             request_subdomain
           end

  tenant.presence
end
host_valid?(host) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 87
def host_valid?(host)
  !ip_host?(host) && domain_valid?(host)
end
ip_host?(host) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 91
def ip_host?(host)
  !/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/.match(host).nil?
end
parse_host(host) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 99
def parse_host(host)
  (PublicSuffix.parse(host, ignore_private: true).trd || '').split('.')
end
subdomain(host) click to toggle source

Only care about the first subdomain for the database name

# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 79
def subdomain(host)
  subdomains(host).first
end
subdomains(host) click to toggle source
# File lib/ekylibre/multi_tenancy/middleware/container_aware_rack_middleware.rb, line 83
def subdomains(host)
  host_valid?(host) ? parse_host(host) : []
end