Can't preload association when creating an entity

Hello guys I can’t figure out why my association is not preloaded in my view.
When I POST an image with the associated category I’m getting a Internal Server Error because I’ve added in my image view the category’s view :

defmodule ApiAppWeb.ImageView do
  use ApiAppWeb, :view
  alias ApiAppWeb.ImageView

  def render("index.json", %{image: image}) do
    %{data: render_many(image, ImageView, "image.json")}
  end

  def render("show.json", %{image: image}) do
    %{data: render_one(image, ImageView, "image.json")}
  end

  def render("image.json", %{image: image}) do
    %{
    id: image.id,
      name: image.name,
      description: image.description,
      image: image.image,
      category: render_one(image.category, ApiAppWeb.CategoriesView, "categories.json" )
      }
  end
end

So I’m getting the not loaded association error : #Ecto.Association.NotLoaded<association :category is not loaded>

But on my list_image method I preloaded the category and I’ve been through the documentation and it references the same way as I did:

  def list_image do
    Image
    |> Repo.all()
    |> Repo.preload(:category)
  end

When I’m trying to debug the problem I can see that when I’m creating a new entry I need to load the association and when I’m making a GET request on my image list, the category view did not load the image association but I do get all the results… this is a little bit weird

Thanks a lot for your help !

UPDATE:

If someone is facing the same problem just preload the association in the controller as :

Index example:

def index(conn, _params) do
    image =
      Images.list_image()
      |> Repo.preload(:category)

    render(conn, "index.json", image: image)
  end

Create example :

def create(conn, %{"image" => image_params}) do
    with {:ok, %Image{} = image} <- Images.create_image(image_params) do
      image =
        image
        |> Repo.preload(:category)

      conn
      |> put_status(:created)
      |> put_resp_header("location", Routes.image_path(conn, :show, image))
      |> render("show.json", image: image)
    end
  end
2 Likes

Opinions may vary but I would say push the preloads to the context file. This will give you a consistent boundary around the data.

Yeah I did but the preload in the context was not working for me I still had :
#Ecto.Association.NotLoaded<association :category is not loaded>

def list_image do
    Image
    |> Repo.all()
    |> Repo.preload(:category)
  end
 
  def get_image!(id) do
    Image
    |> Repo.get!(id)
  end

  def create_image(attrs \\ %{}) do
    %Image{}
    |> Image.changeset(attrs)
    |> Ecto.Changeset.cast_assoc(:category, with: &Categories.changeset/2)
    |> Repo.insert()
  end

  def update_image(%Image{} = image, attrs) do
    image
    |> Image.changeset(attrs)
    |> Repo.preload(:category)
  end

Likely because your get_image! function was not doing preloading.