I am using context
multitenancy in my application. I have two resources Inspection
and User
. The Inspection
resource is on a tenant schema, while the User
resource is on the public schema. The relationship between the two is many-to-one
, meaning an Inspection
belongs to a User
and a user can have(done) many inspections.
In the User resource
has_many :inspections, Inspection
In the Inspection resource
belongs_to :user, User
I have added a policy in the Inspection
resource where in the the user(actor) can only update inspections they are related to like this:
policies do
policy action(:update) do
authorize_if relates_to_actor_via(:user)
end
end
When I save the form, I get this error in the logs:
[warning] Unhandled error in form submission for MyApp.Inspection.update
This error was unhandled because Ash.Error.Unknown.UnknownError does not implement the `AshPhoenix.FormData.Error` protocol.
** (Ash.Error.Unknown.UnknownError) ** (Postgrex.Error) ERROR 42P01 (undefined_table) relation "inspections" does not exist
query: SELECT i0."id" FROM "inspections" AS i0 INNER JOIN "public"."users" AS u1 ON i0."user_id" = u1."id" WHERE (u1."id"::uuid = $1::uuid) AND (i0."id"::uuid = $2::uuid)
As you can see, the query for inspections is run against the public
schema instead of the tenant
schema. I expect the query to be something like this: SELECT i0."id" FROM "<some_tenant_schema>"."inspections" ...
instead of SELECT i0."id" FROM "inspections" ...
I have inspected the changesets, and I can confirm the tenant is being set, even when form is loaded in LiveView, I can see from the query in the logs that data for relationship forms(the form has relationships I have not included here for simplicity) while the form was being composed is being queried on tenant schema.
As for the authorization, it seems it is passing, see the log of the policy breakdown:
[error] Successful authorization: MyApp.Inspection.update
Generated Filter:
user.id == "fac04600-3797-46cb-a97e-67ac15566368"
Policy Breakdown
A check status of `?` implies that the solver did not need to determine that check.
Some checks may look like they failed when in reality there was no need to check them.
Look for policies with `β` and `β` in check statuses.
A check with a `β¬` means that it didn't determine if the policy was authorized or forbidden, and so moved on to the next check.
`π` and `β` mean that the check was responsible for producing an authorized or forbidden (respectively) status.
When viewing successful authorization breakdowns, a `π` means that the policy or check was enforced via a filter.
If no check results in a status (they all have `β¬`) then the policy is assumed to have failed. In some cases, however, the policy
may have just been ignored, as described above.
Policy | π:
condition: action == :update
authorize if: record.user == actor | β | π
So what is the issue?