Idiomatic way to create attribute-specific policies
I'd like to create policies that describe which attributes an actor is allowed to CRUD, based on their attributes and other data in the model. Is there a way to do this without regard to the named action that is performing the operation? For example, I would like the attributes available for an employee record to differ based on whether the actor is themselves, an HR rep, a manager, their manager, etc. and have these policies enforced across all actions that touch those attributes.
Ideally, this would also be enforced transparently in the case that the attributes being requested are not explicitly specified. For example, if a user performs a bare read, they should simply get all—and only—the attributes that they have access to without error. If a user specifically requests a set of attributes containing a subset to which they do not have access, this should error out.
8 Replies
So there isn't currently a way to do this where the policy itself will limit your access
However, there are ways to achieve what you want, generally speaking 🙂
You'd do things like combine a
preparation
(to alter the query) with a policy
(to enforce it)
1. add a policy to enforce this behavior at the policy level (for safety/security)
2. add a query preparation to deselect it in appropriate cases
Ok, if I understand correctly the
policy selecting
is the solution to the first part, alone satisfying the security requirement of applying across actions, and the prepare
gives it the "soft" behavior described in the second.
I suppose there must be a policy changing
etc. as well?Correct. Although in the example I specified it would actually deselect it even if the user had explicitly selected it. So you could do something like
if !Ash.Query.selecting?(query, :attr) do ... deselect(...)
And yep! There is a changing
check
So the way that policy conditions work and checks work is that anything you can use in an individual step you can use as a condition, and vice versa
For example:
and
Are both valid policies (with different meanings)
So you can sort of "phrase" your policies however you like. i.e if you have three specific types of user, you could do
I believe the second doesn't quite have the meaning you'd want in this case, but a macro should be able to perform the inversion in the expected way if it's preferable for concision/expressivity.
Correct, the second would be a strange policy to write 😆
Just wanted to stress the flexibility of check usage in policies/steps
Expanding to:
I think in that case I'd probably do something like
authorize_changes actor_attribute_equals(:admin, true), fields: [:admin_only_a, :admin_only_b]
but yeah that seems like a useful thing
something like thatIt's certainly a smaller macro (;