How to fetch the actor inside validations?

Basically I'm creating a validation that needs to actor to call another api, but the input changeset doesn't contain the actor.
6 Replies
ZachDaniel
ZachDaniel3y ago
You can't access the actor inside of validations If you want to use the actor, use a change, i.e
def change(changeset, _, %{actor: actor}) do
if some_condition() do
Ash.Changeset.add_error(Ash.Error.Invalid.InvalidAttribute.exception(...))
else
changeset
end
end
def change(changeset, _, %{actor: actor}) do
if some_condition() do
Ash.Changeset.add_error(Ash.Error.Invalid.InvalidAttribute.exception(...))
else
changeset
end
end
Blibs
BlibsOP3y ago
Oh, that's a bummer. I will use the change then, but it does seem like a hack
ZachDaniel
ZachDaniel3y ago
What do you need the current user in a validation for? If you need access to the current user, you probably want a policy check
Blibs
BlibsOP3y ago
I want to convert this policy to a validation:
defmodule Marketplace.Markets.Property.Offer.Checks.IsPropertyOpen do
alias Marketplace.Markets.Property.Offer

use Ash.Policy.SimpleCheck

def describe(_), do: "property has open status"

def match?(actor, %{changeset: %{data: %Offer{property_id: property_id}}}, _),
do: do_check(property_id, actor)

def match?(actor, %{changeset: %{arguments: %{property_id: property_id}}}, _),
do: do_check(property_id, actor)

defp do_check(property_id, actor) do
case Marketplace.Markets.Property.get(%{id: property_id}, actor: actor) do
{:ok, %{status: :open}} -> true
_ -> false
end
end
end
defmodule Marketplace.Markets.Property.Offer.Checks.IsPropertyOpen do
alias Marketplace.Markets.Property.Offer

use Ash.Policy.SimpleCheck

def describe(_), do: "property has open status"

def match?(actor, %{changeset: %{data: %Offer{property_id: property_id}}}, _),
do: do_check(property_id, actor)

def match?(actor, %{changeset: %{arguments: %{property_id: property_id}}}, _),
do: do_check(property_id, actor)

defp do_check(property_id, actor) do
case Marketplace.Markets.Property.get(%{id: property_id}, actor: actor) do
{:ok, %{status: :open}} -> true
_ -> false
end
end
end
As you can see, I just need to actor so I can call that get function from another resource
ZachDaniel
ZachDaniel3y ago
Can you pass authorize?: false, actor: nil instead? You don't really want to get the "property that the actor can see" which is what you're doing by providing the actor there Either way: validations are made for "lightweight input validation" If you need to do database queries, you should do it in a change and use a before_action hook
Blibs
BlibsOP3y ago
Got it! I was able to remove the actor in the end

Did you find this page helpful?