This way we'll avoid having all tenant organizations named "CONSUL" by default, and we'll also use different email senders per tenant, which will reduce the change of the emails being marked as spam.
130 lines
2.8 KiB
Ruby
130 lines
2.8 KiB
Ruby
class Tenant < ApplicationRecord
|
|
validates :schema,
|
|
presence: true,
|
|
uniqueness: true,
|
|
exclusion: { in: ->(*) { excluded_subdomains }},
|
|
format: { with: URI::DEFAULT_PARSER.regexp[:HOST] }
|
|
validates :name, presence: true, uniqueness: true
|
|
|
|
after_create :create_schema
|
|
after_update :rename_schema
|
|
after_destroy :destroy_schema
|
|
|
|
def self.resolve_host(host)
|
|
return nil unless Rails.application.config.multitenancy.present?
|
|
return nil if host.blank? || host.match?(Resolv::AddressRegex)
|
|
|
|
host_domain = allowed_domains.find { |domain| host == domain || host.ends_with?(".#{domain}") }
|
|
host.delete_prefix("www.").sub(/\.?#{host_domain}\Z/, "").presence
|
|
end
|
|
|
|
def self.allowed_domains
|
|
dev_domains = %w[localhost lvh.me example.com]
|
|
dev_domains + [default_host]
|
|
end
|
|
|
|
def self.excluded_subdomains
|
|
%w[mail public shared_extensions www]
|
|
end
|
|
|
|
def self.default_url_options
|
|
ActionMailer::Base.default_url_options
|
|
end
|
|
|
|
def self.default_host
|
|
default_url_options[:host]
|
|
end
|
|
|
|
def self.current_url_options
|
|
default_url_options.merge(host: current_host)
|
|
end
|
|
|
|
def self.current_host
|
|
host_for(current_schema)
|
|
end
|
|
|
|
def self.host_for(schema)
|
|
if schema == "public"
|
|
default_host
|
|
elsif default_host == "localhost"
|
|
"#{schema}.lvh.me"
|
|
else
|
|
"#{schema}.#{default_host}"
|
|
end
|
|
end
|
|
|
|
def self.current_secrets
|
|
if default?
|
|
Rails.application.secrets
|
|
else
|
|
@secrets ||= {}
|
|
@cached_rails_secrets ||= Rails.application.secrets
|
|
|
|
if @cached_rails_secrets != Rails.application.secrets
|
|
@secrets = {}
|
|
@cached_rails_secrets = nil
|
|
end
|
|
|
|
@secrets[current_schema] ||= Rails.application.secrets.merge(
|
|
Rails.application.secrets.dig(:tenants, current_schema.to_sym).to_h
|
|
)
|
|
end
|
|
end
|
|
|
|
def self.subfolder_path
|
|
if default?
|
|
""
|
|
else
|
|
File.join("tenants", current_schema)
|
|
end
|
|
end
|
|
|
|
def self.path_with_subfolder(filename_or_folder)
|
|
File.join(subfolder_path, filename_or_folder).delete_prefix("/")
|
|
end
|
|
|
|
def self.default?
|
|
current_schema == "public"
|
|
end
|
|
|
|
def self.current_schema
|
|
Apartment::Tenant.current
|
|
end
|
|
|
|
def self.current
|
|
find_by(schema: current_schema)
|
|
end
|
|
|
|
def self.switch(...)
|
|
Apartment::Tenant.switch(...)
|
|
end
|
|
|
|
def self.run_on_each(&block)
|
|
["public"].union(Apartment.tenant_names).each do |schema|
|
|
switch(schema, &block)
|
|
end
|
|
end
|
|
|
|
def host
|
|
self.class.host_for(schema)
|
|
end
|
|
|
|
private
|
|
|
|
def create_schema
|
|
Apartment::Tenant.create(schema)
|
|
end
|
|
|
|
def rename_schema
|
|
if saved_change_to_schema?
|
|
ActiveRecord::Base.connection.execute(
|
|
"ALTER SCHEMA \"#{schema_before_last_save}\" RENAME TO \"#{schema}\";"
|
|
)
|
|
end
|
|
end
|
|
|
|
def destroy_schema
|
|
Apartment::Tenant.drop(schema)
|
|
end
|
|
end
|