Notes

cast_assoc/3 for updating a subset of associations

30 April 2024

cast_assoc/3 (docs) has as interesting feature: it will only cast data for records that are preloaded.

It’s subtle: I thought all records had to be preloaded to use it. The docs explain this otherwise:

By preloading an association using a custom query you can confine the behavior of cast_assoc/3. This opens up the possibility to work on a subset of the data, instead of all associations in the database.

You can preload a subset by passing a query when you preload:

query = from p in Post, where p.status = :published
author |> Repo.preload(posts: query)

One thing to watch for is that Ecto.Repo.preload/3 won’t do anything if the associations are already loaded. You can override this with force: true

author = author |> Repo.preload(:posts)

query = from p in Post, where p.status = :published

# noop: this does nothing since they are already loaded
author |> Repo.preload(posts: query)

# this will fetch the filtered set of associations
author |> Repo.preload([posts: query], force: true)