26
loading...
This website collects cookies to deliver better user experience
Contract
and tenants company_a
and company_b
, we will find these tables in the database:SELECT * FROM "public"."contracts"; -- is supposed to be empty
SELECT * FROM "company_a"."contracts";
SELECT * FROM "company_b"."contracts";
CREATE OR REPLACE VIEW public.all_contracts AS
SELECT * FROM "company_a"."contracts"
UNION ALL SELECT * FROM "company_b"."contracts"
-- UNION ALL ...
;
SELECT * FROM all_contracts;
# we want to exclude all "public" models, since these data is not distributed
public_table_names = Apartment.excluded_models.map { |model| model.constantize.table_name.remove(/^public\./) }
# create and execute an SQL query to collect all tables from all schemas (= tenants)
class PgTable < ActiveRecord::Base; end
tenants_table_names_sql = PgTable.select(:schemaname, :tablename)
.where(schemaname: Apartment.tenant_names)
.where.not(tablename: public_table_names)
.order(:tablename)
.to_sql
all_pg_tables_rows = ActiveRecord::Base.connection.execute(tenants_table_names_sql)
# The next lines builds and executes the "CREATE OR REPLACE VIEW" query, which is described at the beginning of the article
all_pg_tables_rows.group_by { |row| row['tablename'] }.each do |table_name, pg_tables_rows|
selects_sql = pg_tables_rows.map do |pg_table_row|
"SELECT * FROM \"#{pg_table_row['schemaname']}\".\"#{pg_table_row['tablename']}\""
end
unioned_selects_sql = selects_sql.join(' UNION ALL ')
create_view_sql = "CREATE OR REPLACE VIEW public.all_#{table_name} AS #{unioned_selects_sql}"
ActiveRecord::Base.connection.execute(create_view_sql)
end
class AllContract < ActiveRecord::Base; end
AllContract.where(...) # go crazy here
VIEWS
and cannot (?) be used to insert, modify or delete data.