- The package can be installed by adding
ex_tenant
to your list of dependencies inmix.exs
:
def deps do
[
{:ex_tenant, "~> 0.2.4"}
]
end
- Run:
mix deps.get && mix deps.compile
to retrieve dependencies & compile
- Call the
use ExTenant
macro to inject all the required behaviour into your - Application Repo module to enable all multi-tenancy functions.
In the application Config
file the repo
and tenanted_field
settings need to be configured.
ExTenant will default the tenanted_field setting to be tenant_id
.
config :ex_tenant,
tenant_repo: MyAppRepo,
tenanted_field: "tenant_id",
get_tenant_from_subdomain_func: &your_application_get_tenant_from_subdomain_function/1
- If the
repo
is not configured ExTenant will raise an exception. - the
get_tenant_from_subdomain_func
is optional if you decide to use the Plug - see example below
- In your application
Repo
file call theuse
macro as per this example
def YourApplication.Repo do
use ExTenant,
config: [
otp_app: :name_of_your_elixir_phoenix_app_as_atom,
adapter: Ecto.Adapters.Postgres,
tenanted_field: "tenant_id"
]
end
In order to get the tenant_id
into the progress dictionary in Phoenix
we recommend to use a plug - there you should retrieve the tenant name
from something like the sub domain
in the url. Then using the tenant name
retrieve the tenant
, and call:
- Repo.put_tenant_id(tenant_id)
To insert the
tenant_id
into the process dictionary.
-
An example of how a Plug can be used to insert the tenant_id into the process dictionary
-
Take a look at the module
ExTenant.SubdomainPlug
From here all your Repo callbacks (Repo.get/Repo.one/Repo.all etc) will
have a where clause applied to them with the tenant_id
injected into the clause.
In order to set the tenant_id
on insert
and update
functions the tenant_id
needs to be inserted into the attributes to be inserted. The tenanted_schema
macro & the tenanted()
function inserts the correct belongs_to
tenanted foreign
key based relationship.
Further the cast_tenant
method overloads the standard Ecto.Changeset.cast
function
by injecting the tenant_id
into the params and allowed keys. This function raises
exceptions when the Repo
was not configured correctly in config.exs
and also
if the tenant_id
value is not set in the process_dictionary.
defmodule Post do
use ExTenant.Schema
use ExTenant.Changeset
tenanted_schema "posts" do
field(:name, :string)
field(:body, :string)
tenanted()
end
defp changeset(attrs) do
%__MODULE__{}
|> cast_tenanted(params, [:name, :body])
end
end
NB: If the tenant_id
is not set in the changeset, Repo.insert/update callbacks will raise a Postgrex.Error
(not_null_violation)
- documentation to be added.
- Overrides the Ecto callback
default_options
to inject thetenant_id
- Overrides the Ecto callback
prepare_query
to inject thetenant_id
into a where clause