Hi,
I have a a complex set of policies and validations in my resource. I would like to enable or disable a button depending on if:
A. The record is validate
B. The policies allow the actor to perform the action.
When I was initially starting out I had implemented much of the validation logic as policies.
Now I have migrated many of the checks to validation, as that is what they really are. Violations would bring the data into an illegal state.
The issue is that now my:
<button disabled={
Resource.can_perform_action?(@user, @resource)} >...</button>
Always returns true as the actor is allowed even if the resource is not valid.
I assume there is a function for a dry-run validation of the action, but I cannot find it.
<button disabled={
Resource.valid_for_action?(@user, @resource)
&& Resource.can_perform_action?(@user, @resource)} >...</button>
Something like that. Am I off on the wrong path, should the can_perform_action?
also be performing validations?
No, what you want here is a calculated property that tells you if this is allowed or not I think.
This calculation should/could probably share code with your policies to not repeat yourself.
This was discussed on slack or discord the other day, but I can’t find it now.
Hm, maybe you could give an example of how that might look?
There are like 10-20 validations in some actions that feed into if an action being valid or not.
The way to run validations would be to build a changeset or query for the action and check query_or_changeset.valid?
However, what you’re looking to do can make sense as a new option to can
. I’ve pushed support for this to ash main
if you’d like to try it out.
can_perform_action?(@user, @resource, validate?: true)
2 Likes
I absolutely misread your code (and misunderstood your intention). Apologies
2 Likes
Thanks Zach, that is exactly what I am looking for. I will try it out and report back.
So, I had a change to test out :validate?
on the main branch, and it almost does what I would want except it actually raises an error in case of validation errors.
(elixir 1.17.2) lib/process.ex:864: Process.info/2
(ash 3.4.20) lib/ash/error/changes/invalid_attribute.ex:4: Ash.Error.Changes.InvalidAttribute.exception/1
(ash 3.4.20) lib/ash/changeset/changeset.ex:2988: anonymous fn/3 in Ash.Changeset.do_validation/5
(ash 3.4.20) lib/ash/changeset/changeset.ex:2968: Ash.Changeset.do_validation/5
(elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 3.4.20) lib/ash/changeset/changeset.ex:2329: Ash.Changeset.run_action_changes/6
(ash 3.4.20) lib/ash/changeset/changeset.ex:1819: Ash.Changeset.do_for_action/4
I would probably expect it to just answer false
, and in cases return_errors?
is set i get the list so I can display to they user why it cannot perform an action.
It might an idea to slight change can_*
functions to be either validation, authorization or both. Something like checks:
[:validation, :authorization], and a
return_errors?` flag.
I could see use cases for seeing if an action COULD be done validly if the user had permission, or if the action was permitted.
On the other hand it might just as well be two functions authorized?()
and valid?()
at that point maybe.
Ah, right that isn’t what I was going for. Can you update to latest main? I’ve made it treat invalid as a false result.
Works like a charm now 
It would be very cool to be able to display “why” an button is disabled for validations as well just having the disabled button is not nice UX. I don’t know if can_*
should be the functions for that though… In any case this is already much nicer to use.
If you use can
instead of can?
you can get the error back, which will be Forbidden
for forbidden errors and invalid for changeset errors.
1 Like
Hey, I was looking for some docs regarding it and I can find nothing if I search for can_perform_action
in ash organisation, could anyone point me to proper place?
nvm - got it working with Ash.can?({Social.Posts.Post, :create_post}, @current_user)

1 Like