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.
There is also Ash.set_tenant/1
which sets it in the process dictionary but that feature is going away in 3.0
It looks like this is still possible in Ash 3, did something change since this comment?
It’s been removed. Where do you see that it’s possible?
I think I got mixed up, sorry. I was looking at PlugHelpers.set_tenant/2
1 Like