Is there a plug for setting the tenant?

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 :wave:

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 :slight_smile:

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 :slight_smile:

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