Skip to content

Application based on the Ash's official documentation for multi tenancy utilizing the :attribute strategy

Notifications You must be signed in to change notification settings

dhonysilva/shire

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Shire, multitenacy application with Ash Framework

Application created during the process of learning how to develop applications utilizing the multitenacy capability with Ash Framework.

In other project we studied the :context strategy, which uses postgres schemas where each tenant has its own database schema. On this strategy we can fetch data from each tenant by using the schema name as a prefix. For example, to fetch the tickets from tenant_01, tenant_02 e tenant_03 we can run the following query:

select * from tenant_01.tickets;
select * from tenant_02.tickets;
select * from tenant_03.tickets;

:attribute Multitenancy strategy

For this current project, we're utilizing the :attribute strategy described here. This strategy implies that each tenant has an attribute organization_id that is used to filter the data.

The Ticket resource thas the organization_id Foreign Key, which is used to determine which tenant it belongs to.

select * from tickets;
id subject status organization_id
0d96594d Cable doesn't work open 9e1c0c0a
b6f8ffee Printer doesn't work open b948c8a3
69e44730 Mouse doesn't work open b948c8a3
70c0d2ce Screen broken open 9e1c0c0a
c74350d5 Slow Internet close 9e1c0c0a
83b6c16d Fix the fan close 9e1c0c0a

Each organization represents one tenant on the application. The organizations table has the following structure:

select * from organizations;
id name domain
9e1c0c0a Tenant 01 tenant_01
b948c8a3 Tenant 02 tenant_02

Learn more

I walked through the official Ash Multitenacy documentation while developing this project.

https://hexdocs.pm/ash/multitenancy.html

Kamaro Lambert (visit the project here) has provided two outstanding tutorials on how to work with Multitenancy utilizing the :context strategy and I used all of the instrunctions he provided to build this project. Here are the links to the tutorials:

Setting up the project

To start this Phoenix server:

  • Run mix setup to install and setup dependencies
  • Run mix mix ash.setup to create the database and run the migrations.
  • Start Phoenix endpoint with mix phx.server or inside IEx with iex -S mix phx.server

Now you can visit localhost:4000 from your browser.

The two routes available are:

Working with data

Once you open the application, you can create organizations and tickets.

On the IEx console, you can create organizations by running the following commands:

Shire.Accounts.create_organization(%{name: "Tenant_01", domain: "tenant_01"})

We will receive the following response:

{:ok,
 #Shire.Accounts.Organization<
   __meta__: #Ecto.Schema.Metadata<:loaded, "organizations">,
   id: "912b94c9-2990-427a-824d-1d6fb9b956c3",
   name: "Tenant_01",
   domain: "tenant_01",
   went_live_at: nil,
   email_domains: [],
   inserted_at: ~U[2025-02-02 13:04:48.916403Z],
   updated_at: ~U[2025-02-02 13:04:48.916403Z],
   aggregates: %{},
   calculations: %{},
   ...
 >}

To list all organizations, run the following command:

iex(2)> Shire.Accounts.list_organizations()
[debug] QUERY OK source="organizations" db=1.5ms queue=3.4ms idle=258.4ms
SELECT o0."id", o0."name", o0."domain", o0."email_domains", o0."inserted_at", o0."updated_at", o0."went_live_at" FROM "organizations" AS o0 []
↳ anonymous fn/3 in AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:785
{:ok,
 [
   #Shire.Accounts.Organization<
     __meta__: #Ecto.Schema.Metadata<:loaded, "organizations">,
     id: "912b94c9-2990-427a-824d-1d6fb9b956c3",
     name: "Tenant_01",
     domain: "tenant_01",
     went_live_at: nil,
     email_domains: [],
     inserted_at: ~U[2025-02-02 13:04:48.916403Z],
     updated_at: ~U[2025-02-02 13:04:48.916403Z],
     aggregates: %{},
     calculations: %{},
     ...
   >
 ]}

There are two ways to create a ticket with the IEx console:

Shire.Support.Ticket
|> Ash.Changeset.for_create(:open, %{subject: "Config the printer"})
|> Ash.Changeset.set_tenant("9e1c0c0a-id-organization")
|> Ash.create!()

Or

Shire.Support.open_ticket(%{subject: "Broken cable"}, tenant: "9e1c0c0a-id-organization")

Fetching data

Some ways to fetch data from Tickets:

Shire.Support.Ticket |> Ash.Query.filter(contains(subject, "5")) |> Ash.read!(tenant: "6b44e248-2011-465c-b52e-bf94c7baa950")

And also

Shire.Support.Ticket |> Ash.Query.filter(status == :close and not(contains(subject, "5"))) |> Ash.read!(tenant: "6b44e248-2011-465c-b52e-bf94c7baa950")

Dealing with building artifacts problems

Sometimes there's some incompatibilies with the files on _build folder. In this case, proceed with one of the steps below.

Clear and recompile modules with:

mix compile --force

Clear build artifacts and compile:

rm -rf _build
mix deps.compile
mix compile

About

Application based on the Ash's official documentation for multi tenancy utilizing the :attribute strategy

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published