What's the correct approach to update an actor inside an action
In my system, I have an
Accounts.User
resource that is normally sent to actions as the actor (this is also the resource used in AshAuthentication, etc).
I also have another API called Payments
and inside of it, it has a resource Payments.Customer
.
Both Accounts.User
and Payments.User
uses the same table, the just have some unique fields to it (mostly Accounts.User
has info about authentication like password, email, etc, and Payments.User
info about Stripe customer id, payments methods, etc).
I also have another resources inside Payments
, for example, Payments.Subscription
.
When an action from Payments.Subscription
is called, it will be called with the Accounts.User
as its resource.
The thing is, besides some checks from Accounts.User
(ex. if the user email is confirmed), these actions from the Payments
API also need to check some things related to info only contained in the Payments.Customer
resource (ex. if the user already have an Stripe's customer id set).
The way that I was thinking about handling this is to pass Accounts.User
as the actor and have policies that checks its fields (again, checking if the email is confirmed, etc), and then, inside the action, having, as the first change, a change that will get the current actor, fetch the Payments.Customer
from it, and storing it as the new actor, and then doing the rest of checks (like if the user has a customer id) in subsequent changes.
My first question in this case is: Is this the best approach for that scenario? Would you do that in some other way?
My second question is: If that is the best approach, how can I update the action actor inside a change? I thought about using Ash.Change.set_context to set the new actor, but I'm not sure if that works (I can't test it right now).3 Replies
🤔 I haven't really thought of that kind of use case
and I'm not actually sure if you have a way to update the actor part-way through
I think we pass the
actor
context in from the context that is running the action
I think that, in an ideal world, one of your user resources would be enough to do all of the policies, TBH
even if that means adding calculations on your user resource that fetches the Payments.Customer
information, or vice versa
and then preloading that information when you fetch the userYeah, I was thinking on just adding the bare minimum required fields from the
Payments.Customer
to Accounts.User
so i could check it from the actor, that is fine with the customer_id
which is just a simple nullable string.
The issue is another field that I have called payment_method
which is actually an nullable embedded resource called Payments.Customer.PaymentMethod
, I don't want to have to duplicate that resource in the Accounts
context since I just want to check if that field is nil
or not.. I guess I could maybe just add the attribute as an :map
to the Accounts.User
resource, not sure, I will try that later
Or maybe I will just fetch the Payments.Customer
in a change
and put it inside the changeset
and then use that value instead of the actor.You could do that, yes
Like fetch the customer from the actor, put it into the changeset context and then refer to the context in your checks.