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.

Showing Posts 1 to 10

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

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
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
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews