I'm doing an update on my model and I'm changing an association based on its id column.
# product_params = %{name: "new name", owner_id: 5 (used to be 4), etc....}
def update(conn, %{"id" => product_id, "product" => product_params}) do
changeset =
Product
|> Repo.get(product_id)
|> Repo.preload([{:owner, :profile}]
|> Product.changeset(product_params)
case Repo.update(changeset) do
{:ok, product} ->
conn
|> put_status(201)
|> render("show.json", product: product )
{:error, changeset} ->
conn
|> put_status(422)
|> render("error.json", changeset: changeset)
end
end
When you have the preload in here, the resulting 'product' contains the original owner and now owner with id 5. It's odd because product.owner_id does return 5, but product.owner.id returns 4. All of the corresponding data in the owner is the old owner.
Now I fixed this for myself by moving around some preload logic, but this feels like it's a bug.
*Also I added a second preload after the update to see if that refreshed it the owner but it didnt. owner_id was still 5 and owner.id was still 4.
When I preload an association and update it's association_id column, the result should be the updated data.
That's working as expected. If you change the owner_id manually, it won't reflect in your associations (because that would require doing queries to load the data). So you need to explicitly preload the data again (or in this case possibly not preload it at all since you are changing the id directly).
We can't query for the association in an update query. Do a Repo.preload(..., force: true) to fetch the other associated record.
@josevalim Thanks for the response. So when I call a second Repo.preload after the update happens, is it supposed to still not load the new association? Or is that what @ericmj is referring to and once you load an association to override it then you have to do a force?
What @ericmj said. :)
@ericmj sorry for newbiness, but what do you mean exactly by "We can't query for the association in an update query."
Isn't that what I'm doing when I call Repo.preload before the update call?
@jbhatab No, you are preloading before the update when you still have the old associated id.
LAST QUESTION, I SWEAR.
@ericmj So whenever you preload you have to do a force to override original preloads? I felt like doing another preload after should fix it, right?
If you preload the same association again you need to add force: true, otherwise ecto will not make a new query. Ecto has this behaviour to save you from duplicate queries.
thanks for all the info
Most helpful comment
We can't query for the association in an update query. Do a
Repo.preload(..., force: true)to fetch the other associated record.