Embed `has_one` relationship into resource
Let's say I have a resource A.
It has relationship:
which holds some fields that should be versioned if any changes happen, it has at least one
:a_version
Let's say the AVersion
has the a :price
attribute.
We can define the manual fake "has_one" relationship, by making a query that takes the latest version of AVersion
.
Now, here's question. Is there any way to embed the fields from the latest AVersion
from the fake "has_one" manual relationship into A
so that they can be:
- Accessed at top-level like A.price
- Loaded automatically
as if they were attributes of the A
itself?20 Replies
There are ways, yes. The basic building block there is a
first
aggregate.
that would provide the foo
and bar
fields on the top level resource
And then to load them automatically all the time:
Although I'd suggest finding a way to only load them when necessary πWoah, had no idea this existed, kinda feel bad that it's the second
Topic
in the docs and I hadn't looked at it. That's awesome, thanks!
Although I'd suggest finding a way to only load them when necessary πThe catch is that, there are fields that are used everywhere where the resource is loaded. So there will be no scenario like that probably
π
Bringing this back from the dead solved because the aggragations caused the
:update
action to fail authentication.
For some reason the :read
action that is performed after :update
fails with Ash.Error.Forbidden
on the IsAllowedTenant
check. The :update
without aggregates
was working fine, also doing the :read
action alone is also working.
A
resource:
The A_version
resource:
1/2
IsAllowedTenant
check:
From the logs I've gathered the IsAllowedTenant
check is getting a valid actor, but the query itself doesn't have any information about tenant, so it make sense why it fails.
BUT, the :read
query usually gets it's tenant information from the SetTenantFromActor
prepare. And there's a problem, because when I've logged what SetTenantFromActor
is getting with this "read after update" action, it turns out it does not get an actor at all. The context
in the prepare
function is %{actor: nil, authorize?: nil, tracer: nil}
Interesting. So the read after updating is likely just reading to load the aggregate
We authorize access to aggregates as well
Iβll have to look into that code in a few hours when Iβm back at my computer
Yup, the query that
IsAllowedTenant
is getting is:
and there's no info about tenant whatsoever.
I will try to debug it in the meantime, but so far I've just got lost in the codebase πOh, interesting actually:
Itβs the parent query that is failing. That is probably a bug. We shouldnβt be reauthorizing the parent query again to load data.
Also the log from the
verbose?: true
option of the :update
1/2
Can I see your IsAllowedTenant check?
Oh, yeah sorry π
Okay, back at my computer
First thing that we should confirm: if you remove the aggregates, it just all works?
Yup
Okay, interesting
I should be able to reproduce this π
What I'm currently checking is that in the
Ash.Actions.Load:445
in the load_request
there are opts
which contain an actor, they are passed to the data
option, but the actor is not explicitly set in the Request.new
take a look at
lib/ash/actions/read.ex
line 346
can you IO.inspect
the value we're setting for that :authorize?
?
nvm I found the problem π
So this is us authorizing the actual aggregate. The reason you aren't seeing it in the verbose logs is because in update
when we're loading we aren't passing through the verbose
flag
The problematic line is lib/ash/query/aggregate.ex
line 393
The base query we're creating for authorizing the aggregate does not contain the actor/tenant (this was a recent-ish change, sorry about that)
will push a fix up shortlyShoot! I was looking at this function like an hour ago, so close xD Well, it didn't break anything that existed in our system, we are just introducing it π
Thanks! β€οΈ
Okay, took longer than I thought, but also ended up adding some much needed options to aggregates. Mind giving it a try now @Myrmyr ?
Sadly I've just finished work and left computer in the office, I can test it tomorrow but ideally on Monday :/
No worries π
It's working π Thanks a lot!