I am trying to build a Multi-Tenant application in Phoenix. The approach am using is creating a Postgres schema for each tenant, with Triplex
doing the heavy lifting. The schema to run a query on can be determined by getting the subdomain from the url using the Triplex.SubdomainPlug
. The Triplex.SubdomainPlug
also sets the current_tenant in the Plug
Conn
, so in my controller I can do conn.assigns[:current_tenant]
to get the tenant, which in this case is a schema to run queries on. What I don’t want is to pass down the tenant schema all the way from the Conn to the Ecto query.
What I have tried so far is, I create a custom Plug, which puts the tenant retrieved by Triplex.SubdomainPlug
in the current Process dictionary. For example
Put the tenant in Conn with Triplex.SubdomainPlug in router.ex
plug Triplex.SubdomainPlug,
endpoint: MyAppWeb.Endpoint,
tenant_handler: &MyAppWeb.TenantHelper.tenant_handler/1
If the domain is http://tenant1.localhost:4000, the Triplex.SubdomainPlug will put "tenant1" as the tenant under the :current_tenant key in conn.assigns.
then get the tenant in the Conn and put it in the Process dictionary:
defmodule MyAppWeb.PutTenant do
alias MyApp.Repo
def init(config), do: config
def call(conn, config) do
tenant = conn.assigns[:current_tenant] || conn.assigns[:raw_current_tenant]
Process.put(:tenant, tenant)
conn
end
end
and plug it in my router:
plug MyAppWeb.PutTenant, otp_app: :my_app
then when performing queries I just do something like this:
alias MyApp.Todo
tenant = Process.get(:tenant)
todo = %{title: "My Todo", description: "Description"}
changeset = Todo.changeset(
%Todo{}
|> Ecto.put_meta(:prefix, tenant),
todo
)
Repo.insert(changeset)
This is working well so far
So my question is it possible set the prefix Ecto globally(in the context of each request), so that every query will run on the set prefix/schema without specifying a prefix/schema in every Repo query?
Will really appreciate your answers. Thank you