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.15.17 ). 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?
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.
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
# OTHER STUFF .....
defaults [:read, :update]
read :list_visits_paginated do
pagination keyset?: true, default_limit: 100
update :update_visit do
create :create_visit do
accept [ :scheduled_for]
change relate_actor(:user, allow_nil?: false)
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
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?
AshJsonApi will automatically use tenant/actor information set using
So you only need to manually thread the tenant through in things like LiveView or any custom calls to Ash.