relates_to_actor_attribute_via

I have a resource called Actor that is not backed by the database, it looks something like this:
defmodule Ht.Actor do
use Ash.Resource, data_layer: Ash.DataLayer.Ets

relationships do
belongs_to :user, Ht.User
belongs_to :role, Ht.Role
end
end
defmodule Ht.Actor do
use Ash.Resource, data_layer: Ash.DataLayer.Ets

relationships do
belongs_to :user, Ht.User
belongs_to :role, Ht.Role
end
end
The user will always be set, and the role will sometimes be set. I want to be able to write policies for both cases. What I have done up until now is pass either the user or the role to Ash.PlugHelpers.set_actor(), which lets me write policies like this:
policies do
bypass Ht.Policy.Checks.actor_is(Ht.User) do
authorize_if action_type(:read) && relates_to_actor_via([:accounts, :user])
end

bypass Ht.Policy.Checks.actor_is(Ht.Role) do
authorize_if action_type(:read) && relates_to_actor_via([:accounts, :roles])
end

policy always() do
forbid_if always()
end
end
policies do
bypass Ht.Policy.Checks.actor_is(Ht.User) do
authorize_if action_type(:read) && relates_to_actor_via([:accounts, :user])
end

bypass Ht.Policy.Checks.actor_is(Ht.Role) do
authorize_if action_type(:read) && relates_to_actor_via([:accounts, :roles])
end

policy always() do
forbid_if always()
end
end
My preferred choice has always been to pass the actual actor record to Ash.PlugHelpers.set_actor() instead of user or role, however I wasn't able to get this to work with relates_to_actor_via. I now need to add more data to my Actor resource, and have it available in a custom read, so I am looking for a way to make it work. First I looked for a way to set some context at the same place I call set_actor however it looks like that context is not passed into a custom read. I am considering a new check relates_to_actor_attribute_via. That way I can pass my full actor record to set_actor and write my policies on the necessary actor attribute. The other possible solution is having a way to specify arbitrary context on the connection that is passed to read actions, etc in the same way actor is. Any thoughts on these approaches?
5 Replies
ZachDaniel
ZachDaniel•3y ago
🤔 I'm not sure I fully understand, but I think you ought to be able to make a custom version of relates_to_actor_via that looks for the actor in the user key like you have it
Alan Heywood
Alan HeywoodOP•3y ago
Thanks, i'll give it a try and see how it turns out.
ZachDaniel
ZachDaniel•3y ago
We could also add an option to the built in one that says where to get the actor from the record i.e relates_to_actor_via(:foo, actor_at: [:actor]) although FWIW its mostly just a wrapper around exists(foo, id == ^actor(:id)) So you could try exists(foo, id == ^actor([:actor, :id]))
Alan Heywood
Alan HeywoodOP•3y ago
It looks like there are some smarts in there relating to navigating has_many relationships etc, so adding the option makes sense to me. I will try it
Alan Heywood
Alan HeywoodOP•3y ago
GitHub
improvement: add :subfield option to relates_to_actor_via by ahey ·...
Allow a subfield to be passed to relates_to_actor_via in cases where the resource relates to a subfield of the actor.

Did you find this page helpful?