I have a rails 4.2 multi-tenant app using the Apartment gem which has been awesome.
Each company has their own subdomain. I'm using a custom "elevator" which looks at the full request host to determine which "Tenant" should be loaded.
When I create a new company I have an after_create hook to create the new tenant with the proper request host.
This always seems to require a restart of the server both in development and production otherwise I get a Tenant Not Found error.
It's using sqlite in development and postgres in production.
Do I really have to restart the server each time I create a new tenant? Is there an automated way to do this? Maybe just reloading the initializer will work, but I'm not sure how to do that/if that's possible?
I have been messing around with this for a month and haven't been able to find a solution that works. Please help!
initializers/apartment.rb
require 'apartment/elevators/host_hash'
config.tenant_names = lambda { Company.pluck :request_host }
Rails.application.config.middleware.use 'Apartment::Elevators::HostHash', Company.full_hosts_hash
initializers/host_hash.rb
require 'apartment/elevators/generic'
module Apartment
module Elevators
class HostHash < Generic
def initialize(app, hash = {}, processor = nil)
super app, processor
@hash = hash
end
def parse_tenant_name(request)
if request.host.split('.').first == "www"
nil
else
raise TenantNotFound,
"Cannot find tenant for host #{request.host}" unless @hash.has_key?(request.host)
@hash[request.host]
end
end
end
end
end
Company Model
after_create :create_tenant
def self.full_hosts_hash
Company.all.inject(Hash.new) do |hash, company|
hash[company.request_host] = company.request_host
hash
end
end
private
def create_tenant
Apartment::Tenant.create(request_host)
end
What ended up working
I changed the elevator configuration to get away from the HostHash one that's in the apartment gem and used a completely custom one. Mostly based off of an issue on the apartment gem github: https://github.com/influitive/apartment/issues/280
initializers/apartment.rb
Rails.application.config.middleware.use 'BaseSite::BaseElevator'
app/middleware/base_site.rb
require 'apartment/elevators/generic'
module BaseSite
class BaseElevator < Apartment::Elevators::Generic
def parse_tenant_name(request)
company = Company.find_by_request_host(request.host)
return company.request_host unless company.nil?
fail StandardError, "No website found at #{request.host} not found"
end
end
end