How does it make sense for an ID not to be found, but for it to be displayed in the loaded information?

{ok, vote} ->
IO.inspect(vote)

%{
  vote: %App.Votes.Vote{
    __meta__: #Ecto.Schema.Metadata<:loaded, "votes">,
    id: 10,
    value: 1,
    user_id: 2,
    user: #Ecto.Association.NotLoaded<association :user is not loaded>,
    post_id: 6,
    post: #Ecto.Association.NotLoaded<association :post is not loaded>,
    comment_id: nil,
    comment: #Ecto.Association.NotLoaded<association :comment is not loaded>,
    inserted_at: ~N[2023-03-20 18:24:01],
    updated_at: ~N[2023-03-20 18:24:01]
  }
}
[error] GenServer #PID<0.815.0> terminating
** (KeyError) key :id not found in: %{vote: %App.Votes.Vote{__meta__: #Ecto.Schema.Metadata<:loaded, "votes">, id: 10, value: 1, user_id: 2, user: #Ecto.Association.NotLoaded<association :user is not loaded>, post_id: 6, post: #Ecto.Association.NotLoaded<association :post is not loaded>, comment_id: nil, comment: #Ecto.Association.NotLoaded<association :comment is not loaded>, inserted_at: ~N[2023-03-20 18:24:01], updated_at: ~N[2023-03-20 18:24:01]}}

I’m beyond confused currently. Why am I unable to access the ID using vote.id in this situation? I don’t get how the IO.inspect can display the ID and the loaded data can display the ID yet I cannot access it.

because id is an attribute of the App.Votes.Vote struct inside the map:

iex(1)> defmodule App.Votes.Vote, do: defstruct [:id]
[..]

iex(2)> vote =  %{vote: %App.Votes.Vote{id: 42}}        
%{vote: %App.Votes.Vote{id: 42}}

iex(3)> vote.vote.id                          
42

hth

1 Like

Your vote struct is embedded in a map so you’d get the ID by doing vote.vote.id.

Interesting. I realised after I made the post where my issue was, but I’ve always found the wording odd whenever I recieve an error like this and I don’t quite have a full grasp on Elixirs inner workings yet

Thanks for that, it makes it clearer for me in the future when I get issues like this

Thank you for this. I’ve had this error in the past as well and the wording always confuses me

What’s confusing? The error message is IMO helpful: shows you the data structure that failed to find the field you’re looking for, no?

How would you change the error message?

It’s often helpful to grab the data from the error message and put somewhere you can format the output a bit so see what it exactly is.
In your case it could make more obvious that you had a map with a struct inside it.

I’m kind of at the just doing things stage of learning so to be honest I wouldn’t have thought the issue was a struct inside a map as thats a bit higher level thinking than I’m capable of currently.

I feel like I can do a lot of things in Elixir and Phoenix, but I’d be lying if I said I actually understood most of what I’ve done at any sort of intelligent level :slight_smile:

I’ve learnt pretty much everything from trial and error + disecting any existing code I can find that seems relevant

Consider this:

x = %{
  a: %{
    b: %{
      c: 1
    }
  }
}

You’d get the 1 value by doing x.a.b.c – it’s all a matter of just following parentheses (in this case curly braces). :smiley:

Don’t beat yourself over it, once you are comfortable with the syntax it becomes elementary. It’s only a matter of habit really.

This is not updated for Phoenix 1.7 yet but still, check it out: GitHub - tamanugi/realworld-phoenix: Exemplary real world application built with Elixir+Phoenix https://realworld.io

Oh I’ve found pretty much everything that exists already in terms of open source projects I think. I’m normally fine with getting values as I have stuff like this in my project already so I can go inception level deep pretty comfortably.

<%= user_notification.notification.current_user.username %>

I’ve never actually thought about or learned about how it is actually working though in terms of maps and structs. I learned how to do it and just did it if that makes sense.

My issue with the error in my original post was that I was returning {:ok, vote} from my query as a case condition, and was trying to access just vote on its own. My query was basically stupid so it messed up how I normally do things. Changed the query to just return vote normally and vote.id worked fine.

2 Likes