A simple and effective way to build multitenant applications on top of Ecto.
Triplex leverages database data segregation techniques (such as Postgres schemas) to keep tenant-specific data separated, while allowing you to continue using the Ecto functions you are familiar with.
-
Add
triplexto your list of dependencies inmix.exs:def deps do [ {:triplex, "~> 1.3.0"}, ] end
-
Run in your shell:
mix deps.get
Configure the Repo you will use to execute the database commands with:
config :triplex, repo: ExampleApp.Repo
The unit tests run, by default, against both PostgreSQL and MySQL. It is possible to run the tests
against only one or the other by setting the TRIPLEX_TEST_BACKENDS environment variable to a
comma-separated list. The recognized values are pgsql and mysql.
This command would run only the PostgreSQL tests:
TRIPLEX_TEST_BACKENDS="pgsql" mix test
In MySQL, each tenant will have its own MySQL database.
Triplex used to use a table called tenants in the main Repo to keep track of the different tenants.
If you wish to keep this behavior, generate the migration that will create the table by running:
mix triplex.mysql.installAnd then create the table:
mix ecto.migrateFinally, configure Triplex to use the tenants table:
config :triplex, tenant_table: :"information_schema.schemata"Otherwise, Triplex will continue to use the information_schema.schemata table as the default behavior for storing tenants.
Here is a quick overview of what you can do with triplex!
Triplex.create("your_tenant")This will create a new database schema and run your migrations—which may take a while depending on your application.
Triplex.rename("your_tenant", "my_tenant")This is not something you should need to do often. :-)
Triplex.drop("my_tenant")More information on the API can be found in documentation.
To create a migration to run across tenant schemas:
mix triplex.gen.migration your_migration_nameIf migrating an existing project to use Triplex, you can move some or all of your existing migrations from priv/YOUR_REPO/migrations to priv/YOUR_REPO/tenant_migrations.
Triplex and Ecto will automatically add prefixes to standard migration functions. If you have custom SQL in your migrations, you will need to use the prefix function provided by Ecto. e.g.
def up do
execute "CREATE INDEX name_trgm_index ON #{prefix()}.users USING gin (nam gin_trgm_ops);"
endmix triplex.migrateThis will migrate all of your existing tenants, one by one. In the case of failure, the next run will continue from where it stopped.
Your Ecto usage only needs the prefix option. Triplex provides a helper to coerce the tenant value into the proper format, e.g.:
Repo.all(User, prefix: Triplex.to_prefix("my_tenant"))
Repo.get!(User, 123, prefix: Triplex.to_prefix("my_tenant"))Triplex includes configurable plugs that you can use to load the current tenant in your application.
Here is an example loading the tenant from the current subdomain:
plug Triplex.SubdomainPlug, endpoint: MyApp.EndpointFor more information, check the Triplex.Plug documentation for an overview of our plugs.
This lib is inspired by the gem apartment, which does the same thing in Ruby on Rails world. We also give credit (and a lot of thanks) to @Dania02525 for the work on apartmentex. A lot of the work here is based on what she has done there. And also to @jeffdeville, who forked (tenantex) taking a different approach, which gave us additional ideas.
Copyright (c) 2017 ateliware
This work is free. You can redistribute it and/or modify it under the terms of the MIT License. See the LICENSE.md file for more details.