Setting attributes after getting data in before_transaction - calling validation in change_attribute

I have a User resource which requires email and a name. I want to expose a create type action on this resource, but all I have available when calling the action is a token. That token is in a 3rd party system, which returns the name and email. This resource has global validation on name and email, which I'd rather not change (or mark as before_action?: true) since I do want them to be run up front for other actions. What I was hoping to do is in a before_transaction block, make the API call to get the data and set the attributes with change_attribute, or put them in a context and call set_attribute in a change block. However, when I do this, since the initial changeset doesn't have an email, it fails validation and the before_transaction never runs. If I pass in a placeholder email, I can get the before_transaction to run, but then I get warnings when calling change_attribute because the changeset has already been validated, and it's actually possible to pass in a bad email here and it'll get written to the database. Another idea I had was to try and do this as a generic action, and then in the run block I would make the API call, get the user data, and then manually call the existing :create . However, I need to return metadata (access tokens) for the user, but it seems like generic actions don't allow for metadata blocks, and since this action will be exposed via GraphQL, I'd want that typing of the metadata attributes on the query/mutation. Basically, I want to expose an action on a user resource that accepts a token as an argument, turns that into user_info and oauth_tokens and then can do the equivalent of the :register_with_google action in the Ash Authentication docs, returning the access token for the user as a metadata field. Note, I'll never really call this in a form, so I'm ok if the fields don't get validated until writing to the persistence layer (postgres in my case), but I do want them to be validated at some point.
5 Replies
barnabasj
barnabasj3mo ago
I think you still need to use force_change_attribute in before_transaction but as the validation now runs after in before_action it should still validate those attributes
Chaz Watkins
Chaz Watkins3mo ago
That works great if you have it set to allow_nil? false
mikewilson
mikewilsonOP3mo ago
Oh nice, I didn't see those. It looks like both delay_global_validations and allow_nil_input would serve my needs. Though it seems like since i'm not accepting email or name as an argument then allow_nil_input wouldn't really apply in my case. I think delay_global_validations plus using force_change_attribute to remove the warning is enough to unblock me. Thanks!

Did you find this page helpful?