Check if an identity exists in a before_action
I'm not quite sure how to accomplish this in Ash:
I'm uploading files to GCS and want to make sure if the hash of the file matches one I already have, I don't upload it again. The upload happens in a
before_action
on create right now. The hash of the file is an identity, and I thought eager checking would prevent the upload but it doesn't seem to.
I'd like the create_with_binary
to return the original record if it exists (without uploading) or upload and create a new record if necessary. So basically find_or_create
.
Here's the code so far:
37 Replies
I think that might be all you need
i wasn't able to find many docs on the upsert - does that prevent the before_action from running?
eager_check_with
will do its work before before_action
hooks are run, which is why you probably saw no change on that
Nope
Ah, I seei think i might need to manually do a read of the database and then block the rest of the action from executing, returning the thing that was read
but not sure how to do that in the
before_action
you need to make sure not to upsert if one exists already.
Ash.Changeset.set_result
lets you have a sort of "conditional" manual action, where sometimes the result is computed by you and other times you let Ash execute the action.ooh that's really cool haha
trying it now
silly thing but is there a way to call get on the AudioFile and not the associated API
like rather than:
Scribble.EmailHandler.get(AudioFile, hash: filename)
Have you looked into the code interface yet?
will get you
oh yes I've done that but I meant rather than having to use
Scribe.EmailHandler.get_by_hash
or Scribe.EmailHandler.get
I'd want to do :
Scribe.EmailHandler.AudioFile.get
or somethingOh, interesting
it's a small thing but it feels like an
AudioFile
should know how to get itself
in case I move it somewhere else laterNothing to do that currently, although you can always do
in your resource
One thing you may need to do is lock the record in the database to prevent multiple of these actions happening side by side. Ash doesn't currently support that natively, so you may want to do something like this:
it's a little confusing to me that :
this defines functions on
Scribble.EmailHandler.<Resource>
when it says define_for Scribble.EmailHandler
i like that behavior I just don't quite get the syntaxYes,
define_for
is which api the generated functions will call under the hood
because all action invocations always go through an api moduleah so that way any extensions in the API apply to that resource
Yep, and there are certain rules like authorization configuration/timeouts and things like that that can be configured at the api level
i'd love a video on how ash works under the hood whenever you get to it š always helps me understand how to use something properly when I get the mental model behind it
For sure š
We're also working to make that code generally more understandable by using
Ash.Flow
Ash.Flow
can auto generate flow charts for a given operation, and so ideally we can create an Ash.Flow
for the various parts of our system, and then explain any given thing by generating the diagram of it
or at least allow for a way to see that behavior laid out without having to read the code
but that will probably be a while šthis didn't seem to work
I'm getting the error that :url is required, :hash is required
oh interesting...
See if this helps
actually hang on...
is there a stacktrace there?
There is probably a check we are doing that we shouldn't do if
set_result
has been used š
that's my code right now
no stacktrace
it's returning an
{:error, %Ash.Error.Invalid...}
can you use the
!
version of the function you're calling?
should see some stacktraces there
what's interesting is I'm inspecting the changeset after set_result and the data does look like it's nil for some reason
Yeah, thats fine š
The way we set the result is into the
context
key which is hidden there
well, trimmed down
can you try main
?
I just pushed something up that ought to fix ityup trying it now
hmm did something change between main and 2.6 about how code_interfaces work
my case clause is failing
š¤ don't think so
does it no longer return {:ok, ...}
If so its a bug
did you add a
!
to the call?
that will cause it not to return {:ok,
nope
š¤ so
get_by_hash
is in your code interface, and its returning %Record{}
?yes
but on failure it's returning an
{:error, _}
here's the case:
^ this worksš¤
and here's the code interface:
oh, actually are you sure its your case statement?
I think its because you need to do
Ash.Changeset.set_result(changeset, {:ok, audio_file})
I forgot about thatthat worked!
Yeah, so it was actually the case statement in the create function
cool everything's working now
š
thanks!
š