caslu

caslu

Hello guys! I’m developing an API only Phoenix project for pet donations, and at the moment i have the following schemas:

  • User schema:
  schema "users" do
    field :name, :string
    field :email, :string
    field :bio, :string
    field :avatar, :string
    field :website, :string
    field :phone, :string
    field :social_links, {:array, :string}
    field :roles, {:array, Ecto.Enum}, values: [:ADOPTER, :DONOR]
    has_many :pets, Announcements.Pet, foreign_key: :owner_id

    timestamps(type: :utc_datetime)
  end
  • Pet schema:
  schema "pets" do
    field :name, :string
    field :size, :decimal
    field :bio, :string
    field :photos, {:array, :string}
    field :age, :integer
    field :gender, Ecto.Enum, values: [:MALE, :FEMALE]
    field :species, Ecto.Enum, values: [:DOG, :CAT]
    field :vaccinated, :boolean, default: false
    field :dewormed, :boolean, default: false
    field :neutered, :boolean, default: false
    field :disability, :boolean, default: false
    field :pedigree, :boolean, default: false
    field :weight, :decimal
    belongs_to :user, Accounts.User, foreign_key: :owner_id
    belongs_to :breed, Announcements.Breed, foreign_key: :breed_id

    timestamps(type: :utc_datetime)
  end
  • and the Breed schema:
  schema "breeds" do
    field :name, :string
    field :temperaments, {:array, :string}
    has_many :pets, Announcements.Pet, foreign_key: :breed_id

    timestamps(type: :utc_datetime)
  end

As you can see, the relations above are pretty simple actually, users can own many pets announces and therefore each pet announcement belongs to a user, each pet belongs to a breed, and this specific breed can own a lot announcements, so another many to one relationship.

The problem is around pets and breeds, when i insert a pet, breed or user everything looks fine, but when i trigger the show action on pets_controller the Jason complains that it’s unable to encode because of NotLoaded Association. I know there's questions similars and i know i could preloadthe breeds association with pets, but the weird fact for me is that Jason does not complain if i don't preload the:userassociation, and when i triggershowaction ofuser_controller` Jason does the encoding pretty well even with not loaded pet associations, so what i want to understand is why this error is happening with only one association.

First 10 of 18 Posts Switch mode

cmo

cmo

I think you’ll need to show the code that is loading stuff from the database.

03juan

03juan

This sounds like the same kind of issue I answered in another post recently. Ecto `change/2` preloading associations? - #3 by 03juan

Basically when you build a new struct, the change function replaces NotLoaded with the respective “empty” value, nil for belongs_to and has_one or [] for has_many, specifically for things like forms so you don’t have to do it manually. But when you’re loading an existing record from the db you have to preload the association to replace the NotLoaded struct before you access the data.

Since you mention Jason I assume you’re setting up your own api controller. If you want to send the base struct without having to preload, the you can either @derive {Jason.Encoder, except: [:user, :breed]} above the schema "pets" declaration, which will always strip out those keys when serialising, or manually define your own protocol implementation so you can send the nested user and breed when they’re preloaded or exclude those keys when their values are NotLoaded.

See the defimpl Jason.Encoder example and let us know how it goes.

caslu

caslu OP

Just a regular Repo.get! function is enough to trigger the error

caslu

caslu OP

I’ve tried the derive on pets schema but had not successful at all, Jason still complained about the Not Loaded Association

03juan

03juan

I’m sorry, my code is actually incomplete, you also have to exclude the :__meta__ key or it fails with ** (RuntimeError) cannot encode metadata from the :__meta__ field. However it should have removed the other keys and not complain about NotLoaded.

Please post the code for your derivation and the output from an iex session showing the failure, or how you’re using the struct in your controller.

Can’t help any more than this without it…

Does Repo.get!(Announcements.Pet, pet_id) error in iex?

dimitarvp

dimitarvp

You likely have this somewhere in your controller(s)?

|> json(...)
caslu

caslu OP

It doesn’t because the problem is not with Ecto, just related, the problem is when Jason tries to encode it, at the moment my code snippet of pet schema is just like that:

  @derive {Jason.Encoder, except: [:user, :breed, :__meta__]}
  schema "pets" do
    field :name, :string
    field :size, :decimal
    field :bio, :string
    field :photos, {:array, :string}
    ....

Even with the @derive clause, Jason seems just to ignore, don’t know why, the error remains the same:

(RuntimeError) cannot encode association :breed from PontoCao.Announcements.Pet to JSON because the association was not loaded.

caslu

caslu OP

Don’t mate, the show action of pet_controller looks just like the phoenix auto generate:

def show(conn, %{"id" => id}) do
    pet = Announcements.get_pet!(id)
    render(conn, :show, pet: pet)
end

And the Announcements.get_pet!/1 is just a Repo.get!/1 call

D4no0

D4no0

First of all, ideally you should have a render file where you decide what shape the return will have, it should look the following (this one was generated using mix phx.gen.json Accounts User users name:string age:integer):

defmodule PhoenixTestWeb.UserJSON do
  alias PhoenixTest.Accounts.User

  @doc """
  Renders a list of users.
  """
  def index(%{users: users}) do
    %{data: for(user <- users, do: data(user))}
  end

  @doc """
  Renders a single user.
  """
  def show(%{user: user}) do
    %{data: data(user)}
  end

  defp data(%User{} = user) do
    %{
      id: user.id,
      name: user.name,
      age: user.age
    }
  end
end

There you can dictate what you render, it also decouples your controller from your schema.

As for error you are getting, you cannot render associations that are not preloaded. There are 2 options of doing that:

  1. Using Repo.preload/3: Ecto.Repo — Ecto v3.14.0
  2. Using preload from query: Ecto.Query — Ecto v3.14.0

Otherwise if you don’t need them, don’t render them.

03juan

03juan

Yes it’s because there is a NotLoaded value that you haven’t removed or replaced before Jason tries to encode it.

But this is very weird. What does your heex code look like?

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement