Home

Awesome

CircleCI

Tenantex

Tenantex is a fork of https://github.com/Dania02525/apartmentex There was some fantastic work done there, but I wanted to take a slightly different approach.

Easy SaaS for Phoenix/Ecto.

In this branch, the following versions are supported:

Features

Setup

{:tenantex, "~> 0.1.0"}
config :tenantex, schema_prefix: "prefix_" # the default prefix is "tenant_"

Use

Generate a migration file that will be run against each tenant:

mix tenantex.gen.migration CreateUsers

By default, the migration will be generated to the "priv/YOUR_REPO/tenant_migrations" directory of the current application but it can be configured to be any subdirectory of priv by specifying the :priv key under the repository configuration.

You can now add a new tenant and automatically create a new schema for Postgres users or a new database for MySQL users, and run the migrations in priv/YOUR_REPO/tenant_migrations for that schema or database.

Table references and indexes in a migration will be applied to the same tenant prefix as the table within tenant_migrations.

Tenantex.new_tenant(Repo, tenant)

When you need to update a tenant's schema based on new migrations, you can run:

# Runs all migrations necessary for the tenant, based on that tenant's
`schema_migrations` table
# Returns a tuple that is either:
# {:ok, prefix_of_tenant, versions_migrated}
# {:error, prefix_of_tenant, db_error_message}

{status, prefix, versions_or_error} = Tenantex.migrate_tenant(Repo, tenant)

If there is a problem with a migration, you can roll it back by passing in the version (as an integer). This will revert every migration back until the version specified (including that version):

# Returns a tuple that is either:
# {:ok, prefix_of_tenant, versions_rolled_back}
# {:error, prefix_of_tenant, db_error_message}

{status, prefix, versions_or_error} = Tenantex.migrate_tenant(Repo, tenant, :down, to: 20160711125401)

When deleting a tenant, you can also automatically drop their associated schema or database (for MySQL).

Tenantex.drop_tenant(Repo, tenant)

To Do