I am building an app where users can belong to different organizations. I want each organization to be it’s own tenant ( Multitenancy — ash v2.21.5 ). When the user is logged in, they select a tenant, and can only have access to data from that tenant.
Is there a way call set_tenant in a router plug ( similar to Ash.PlugHelpers.set_actor(user) ) so that I can globally set the current tenant, without for any queries that might need it?
1 Like
Hi there
There is Ash.PlugHelpers.set_tenant/2
.
The thing to note is that the Ash plughelpers are there to provide a consistent interface across various extensions that interact with plugs - ie AshJsonApi, AshGraphQl and AshAuthentication. Note that these won’t do anything for your code - you would still need to call get_tenant/2
and pass it into your actions as an option.
There is also Ash.set_tenant/1
which sets it in the process dictionary but that feature is going away in 3.0 on favour of requiring it to be explicitly passed as above.
1 Like
Thank you! What you are saying about set_tenant totally makes sense; however, I don’t quite understand how I would call get_tenant and pass it in as an option. Like, if someone wanted to split a simple resource like the one below across tenants, what changes would you have to make?
defmodule App.API.Visit do
use App.Resource,
api: App.API,
data_layer: AshPostgres.DataLayer,
extensions: [AshGraphql.Resource],
authorizers: [Ash.Policy.Authorizer]
# OTHER STUFF .....
actions do
defaults [:read, :update]
read :list_visits_paginated do
pagination keyset?: true, default_limit: 100
end
update :update_visit do
accept [:scheduled_for]
require_attributes [:scheduled_for]
end
create :create_visit do
accept [ :scheduled_for]
change relate_actor(:user, allow_nil?: false)
end
end
Right. Well the first think is to decide what sort of multitenancy you want and set the resource DSL appropriately. See the guide for a starting point.
Next when you call your actions you set the tenant on the changeset or query using their respective set_tenant
functions. If you’re using the code interface you can pass a tenant:
option in the options keyword list as the last argument in the call.
You can also use the tenant
option to Ash.Query.for_read
and Ash.Changeset.for_create/update/destroy
Ok. Thank you ( and thanks for your patience with me ). It sounds like I need to set the tenant as option when I call the actions in code, or when I do a query. That makes sense to me now
I think I am still confused about AshGraphQl / AshAdmin / AshAuthentication. If I use Ash.PlugHelpers.set_tenant/2
in the router, does that automatically set_tenant on those services and I just don’t need to worry about it? Or is there something I need to do inside of my router or Ash.Api to make it work?
1 Like
Yes, AshGraphql
and AshJsonApi
will automatically use tenant/actor information set using Ash.PlugHelpers
So you only need to manually thread the tenant through in things like LiveView or any custom calls to Ash.