AE
Ash Elixir•2y ago
Blibs

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
ZachDaniel
ZachDaniel•2y ago
🤔 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 user
Blibs
BlibsOP•2y ago
Yeah, 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.
ZachDaniel
ZachDaniel•2y ago
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.

Did you find this page helpful?