I was working on migrating over my app to use 3.0 and I’m running into a weird error. I have a few resource and it seems like most work as expected but one. The resource todo is able to properly create things but not load them. The only difference that might be relevant is that todo uses AshArchival.
todo = Todo.create!(...)
# returns todo
Ash.get(Todo, todo.id)
# returns %Ash.Error.Query.NotFound
Repo.get!(Todo, todo.id)
# returns entity properly with Ecto
The DB queries it forms
# from Ash
SELECT * FROM "todos" AS t0 WHERE (t0."id"::uuid = $1::uuid) LIMIT $2 ["e8fe6f7f-4349-471b-b94a-e36c23cc3f7d", 2]
# from Ecto
SELECT * FROM "todos" AS t0 WHERE (t0."id" = $1) ["e8fe6f7f-4349-471b-b94a-e36c23cc3f7d"]
# working project query from Ash
SELECT * FROM "projects" AS p0 WHERE (p0."id"::uuid = $1::uuid) LIMIT $2 ["ebcb9206-85a8-4686-aa0f
-2eb4e34e5806", 2]
Hmm…those queries don’t really make much sense as they should be completely equivalent.
My suspicion is that you are seeing here is the application of policies to your resource actions.
In Ash 3.0, the default value for authorize?
was changed to true
. In Ash 2.0, authorization would occur when you either provided actor: <something>
or authorize?: true
.
Do you have any policies on the resource in question?
I don’t have any policies on the resource. I could be wrong but after some trial and error it looks like it was linked to preparation/calculations but I would need to take a look at it.
calculations do
calculate(:days_until, :integer, TimeUntil)
end
preparations do
# commenting this line seems to fix it
# prepare(build(load: :days_until))
end
I believe the issue was tied to the calculation that I had. I wanted to conditionally calculate something so I would filter out all the records that did not apply.
@impl true
def calculate(records, _opts, _params) do
records
|> Enum.filter(& &1.due_date_at)
|> Enum.map(fn todo_record ->
DateTime.diff(todo_record.due_date_at, DateTime.utc_now(), :day)
end)
end
end
I reimplemented to set an integer or nil and it seems to work
@impl true
def calculate(records, _opts, _params) do
records
|> Enum.map(fn todo_record ->
calculate_diff(todo_record)
end)
end
defp calculate_diff(%{due_date_at: due_date}) when is_nil(due_date) do
nil
end
defp calculate_diff(%{due_date_at: due_date}) do
DateTime.diff(due_date, DateTime.utc_now(), :day)
end
Ah, interesting…yeah that would have done it. We zip the records up and that could result in missing records. We could add some checks in here that you returned the right number of records, but that would add expensive checks to a hot path, so probably not a good idea.