Hello all,
Its a pleasure to join this community! I just started learning Elixir. I love it so much.
I come from Python.
One of the issues I have been fighting with the Phoenix Web Framework is related to loading schema associations. I still cant fully get the hang of it.
I suspect I am doing something wrong in the relationship definitions.
I am developing a simple app to learn about Elixir.
And it consists of a few schemas:
defmodule NimPhoenix.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias NimPhoenix.Enums.NotificationTimesEnum
@primary_key {:user_id, :binary_id, autogenerate: true}
schema "users" do
field :handle, :string
field :name, :string
field :first_name, :string
field :last_name, :string
field :email, :string
field :password, :string, virtual: true
field :hashed_password, :string
field :active, :boolean, default: true
field :open, :boolean, default: true
field :visible, :boolean, default: true
field :confirmed_at, :utc_datetime
field :notification_time, NotificationTimesEnum, default: :WHENEVER
has_many :thread_participants, NimPhoenix.Messaging.ThreadParticipant,
foreign_key: :user_id
has_many :threads, through: [:thread_participants, :thread]
has_many :messages, NimPhoenix.Messaging.Message,
foreign_key: :sender_id
has_many :bids, NimPhoenix.Messaging.Bid
timestamps(type: :utc_datetime)
end
Bid:
defmodule NimPhoenix.Messaging.Bid do
use Ecto.Schema
import Ecto.Changeset
alias NimPhoenix.Enums.BidTypeEnum
@primary_key {:bid_id, :binary_id, autogenerate: true}
schema "bids" do
field :bid_type, BidTypeEnum
field :nod, :integer
belongs_to :bidder, NimPhoenix.Accounts.User,
foreign_key: :bidder_id,
type: :binary_id
belongs_to :thread, NimPhoenix.Messaging.Thread,
foreign_key: :thread_id,
type: :binary_id
timestamps(type: :utc_datetime)
end
def changeset(bid, attrs) do
bid
|> cast(attrs, [:bid_type, :nod, :bidder_id, :thread_id])
|> validate_required([:bid_type, :bidder_id, :thread_id])
|> validate_inclusion(:nod, 1..365)
end
end
Thread:
defmodule NimPhoenix.Messaging.Thread do
use Ecto.Schema
import Ecto.Changeset
alias NimPhoenix.Enums.NegotiationStateEnum
@primary_key {:thread_id, :binary_id, autogenerate: true}
schema "threads" do
field :nego_state, NegotiationStateEnum, default: :IN_PROGRESS
field :nod_agreed, :integer
has_many :thread_participants, NimPhoenix.Messaging.ThreadParticipant,
foreign_key: :thread_id
has_many :users, through: [:thread_participants, :user]
has_many :messages, NimPhoenix.Messaging.Message,
foreign_key: :thread_id
has_many :bids, NimPhoenix.Messaging.Bid,
foreign_key: :thread_id
timestamps(type: :utc_datetime)
end
def changeset(thread, attrs) do
thread
|> cast(attrs, [:nego_state, :nod_agreed])
|> validate_required([:nego_state])
end
end
In the LiveView html, I want to be able to show the user handle of the last bid. But it was not loaded, so I preload when grabbing the thread, as so:
def get_thread(thread_id) do
thread =
Repo.get(Thread, thread_id)
|> Repo.preload([:thread_participants,:messages, :users, :bids [:bidder]])
if thread, do: {:ok, thread}, else: {:error, :not_found}
end
However, if I add this part to the preload:
bids [:bidder]])
It fails with:
[debug] QUERY OK source="bids" db=0.4ms idle=4.6ms
SELECT b0."bid_id", b0."bid_type", b0."nod", b0."bidder_id", b0."thread_id", b0."inserted_at", b0."updated_at" FROM "bids" AS b0 WHERE (b0."bid_id" = $1) ["070e5ddb-5c54-4503-b896-65630907512d"]
↳ NimPhoenix.Messaging.get_bid/1, at: lib/nim_phoenix/messaging/messaging.ex:179
[error] Task #PID<0.1804.0> started from #PID<0.1745.0> terminating
** (Ecto.QueryError) deps/ecto/lib/ecto/association.ex:1220: field `id` in `where` does not exist in schema NimPhoenix.Messaging.Thread in query:
from t0 in NimPhoenix.Messaging.Thread,
where: t0.id == ^"e6b1d0d5-bcfe-4955-bd23-f14c3cf5b48d",
select: {t0.id, t0}
(elixir 1.17.3) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
(elixir 1.17.3) lib/enum.ex:1829: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(elixir 1.17.3) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.12.4) lib/ecto/repo/queryable.ex:214: Ecto.Repo.Queryable.execute/4
(ecto 3.12.4) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.12.4) lib/ecto/repo/preloader.ex:332: Ecto.Repo.Preloader.fetch_query/8
(elixir 1.17.3) lib/task/supervised.ex:101: Task.Supervised.invoke_mfa/2
(elixir 1.17.3) lib/task/supervised.ex:36: Task.Supervised.reply/4
If I remove it, I am unable to load the user for the bid.
I find it weird how it complains on the id
field. I have no id
fields, so I guess its defaulting to it.