Preload relationship during action
I know we can use
load
to load an association during an action. However this only loads the relationship after the action is completed. I would like to do something like this:
Using :my_resource in the next change doesn't preload the relationship at the moment to I get a #Ash.NotLoaded<:relationship>
.
Im sure this is possible? Wasn't able to figure it out from the docs so wondering if anyone has a similar situation16 Replies
Youd need a custom change to accomplish this
So the change will just do a fetch?
I guess im curious why the load happens after and not inline?
Im curious how the resource gets loaded when it hits an action? For my use case its from the AshJsonApi. Is it possible to preload at that level?
Also my changes after are in an "after action", will it be preloaded by the time im in the after action?
The load happens after since its meant to have the data loaded "after" the action for any thing calling it
but your change could do something accidentally (or on purpose) that would scrub that value
like if you take the loaded record and do something and return it via reloading or something, oops you've accidentally removed the thing that was meant to be loaded
You can programatically use, so if you have a change that wants to load some data during an action, it kinda depends when and where you need it
you can load things programatically if you have the record with things like
Api.load(record, :relationship)
Hm, it still seems a bit weird since the after actions are supposed to be after the action? so the load should be before this I was assuming.
I tried Api.load, which works in the after action, but its doesnt do any optimization for already loaded relationships it seems. Is it possible to preload in the changeset level before an after action?
The after actions aren't really after the "entire action". Its probably a bad name, now that you say it
Its more like
after_data_layer_action
You can do lazy?: true
as an option to your load to not overwrite already loaded stuffAh that makes sense. I guess what im trying to figure out is whats the recommended way to preload stuff to use down the action + changes pipeline. Is it better to have a special change that preloads this? or do you just do it inline where neede?
I typically don't load data in the actions at all TBH
I make the caller ask for what additional data they need
although, I see what you're saying
you have hooks that need the data
In that case yeah I usually do it in-line where I need it or in a custom change. The story there could definitely be better
yeah what would be nice would be something similar to load, say
preload([:relationships])
and would load the relationships if not already loaded.
For context, I typically publish integration events after actions using Oban as an outbox, and serialize the current state of the resource + some relationships into an Oban job to be sent over a message bus, so I run into this sorta stuff all the timeYeah, the main difficult with it is actually the ordering of events
If both of those add an after_action hook, they go in reverse order
like the last-added after_action hook goes first, and so-on
its a stupid problem and honestly....I might change that for 3.0
@jart thoughts?
should we make after_action and before_action hooks go in the order they are added for 3.0?
I think we probably should just because the current behaviour violates the principle of least surprise.
Yeah, because we're mostly composing actions
But also I wonder if there’s not a better way of expressing it to make the dependencies clear to the machine and the user.
and
does not at all look like bar goes before foo. The real difficulty is that sometimes you want to add
after_action
hooks in the core changes block that go after everything
There are some answers. We should revisit for 3.0.
I think for complex workflows it makes sense to use something else, but we also want to enable people not to have to reach for that for relatively simple actions
i.e load some data, do a side effect, return the resultYup.
I was thinking something like
Or something like that that makes the order explicit.
Hmm....
Yeah, its an interesting idea
Maybe we should store alongside the function the config of
prepend?
and append?
and then if something was made with prepend?
and something else is added without prepend?
then it goes after all the prepend?
hooks
Essentially introducing three more meta-phases hah
not that people will really need to think about it that way
it just makes prepend?
and append?
do what you think more often. But it might just be way too confusing. Okay, I think I see what we should do.
In 3.0:
hooks happen in the order that they are added. Both before_action
and after_action
.
the global changes block only, supports before_action_changes?: true | false
(defaulting to true
)
If its within a single action, its easy enough to move them around. Its only the interaction between before/after action. And if the added hooks will be in the proper order, then also the order of the changes will be correct. I think this is the answer that makes things work the way you expect, but lets you choose where global changes happenGitHub
Better action hook order in 3.0 · Issue #724 · ash-project/ash
Right now hook execution order does not follow the principle of least surprise. They happen essentially in reverse order from how they were added. This makes sense in a functional hook builder but ...