Support to_many on actor side in relates_to_actor_via filter check

If the field we want to check inside a resource that has a relates_to_actor_via check is a has_many relationship, relates_to_actor_via will correctly handle that and check each resource inside that list with the actor field.

Now, let’s say we have it the other way around. For example:

Let’s say I have the following resources:

  • School, a school has a has_many relationship with Teacher and has_many relationship with Student;
  • Teacher, a teacher has a has_many relationship with School;
  • TeacherSchool, has a belongs_to relationship with both School and Teacher;
  • Student has a belongs_to relationship with School.

Now let’s say I am a teacher (the actor) and I want to update a student, to allow that, I want to make a policy that will check if the student is enrolled in one of the schools that the current teacher teaches.

This seems like a perfect usage of relates_to_actor_via check using this policy in Student:

policy action(;update) do
  authorize_if relates_to_actor_via(:school, field: :schools)
end

The issue is that relates_to_actor_via will only check for a has_many relationship for the first argument :school, but it will not do the same to the second argument :schools, making the policy fail.

Is it possible to add support for that use case?

You can probably use an expression with the actor template instead, for example:

defmodule Student do
  require Ash.Expr

  belongs_to :school, School
  
  policies do
    policy action(:update) do
      authorize_if expr(school.teacher_schools.teacher_id == ^actor(:id))
    end
  end
end

Small addendum here is that you should use exists in that context. for more: Expressions — ash v3.2.4

as for modeling this, I believe that this is what you are looking for.

  authorize_if relates_to_actor_via([:school, :schools, :teachers])