phoebe
Hi, I’ve been scratching my head around this for a while and trying different combinations, but I’m just stuck whilst using build_assoc which does not recognise binary id UUIDs in my code. Here’s my problem and question.
I’m working on a banking app, so I have a user and wallet. user was created with Pow if that makes any difference. There is a has_many relationship between user and wallet. Here are the schemas:
use MyApp.Schema
schema "users" do
field :role, :string, null: false, default: "user"
has_many :wallets, MyApp.Accounts.Wallet
pow_user_fields()
timestamps()
end
and
use MyApp.Schema
...
schema "wallets" do
field :description, :string
field :balance, Money.Ecto.Composite.Type
belongs_to :user_id, MyApp.Users.User, references: :uuid, type: :binary_id
timestamps()
end
where MyApp.Schema is set up for UUIDs:
defmodule MyApp.Schema do
defmacro __using__(_) do
quote do
use Ecto.Schema
@primary_key {:uuid, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@derive {Phoenix.Param, key: :uuid}
@timestamps_opts
end
end
end
Then in my CreateWallet migration:
defmodule MyApp.Repo.Migrations.CreateWallets do
use Ecto.Migration
def change do
create table(:wallets) do
add :description, :string, null: false
add :balance, :money_with_currency, null: false
add :user_id, references(:users, column: :uuid, type: :binary_id, on_delete: :nothing)
timestamps()
end
create index(:wallets, [:user_id])
end
end
All standard I think so far. However, if I want to implement a create_user_wallet function:
def create_user_wallet(%User{} = user, %{} = wallet_params) do
wallet = Ecto.build_assoc(user, :wallets, wallet_params)
Repo.insert(wallet)
end
and then try to run it, there is an error:
** (KeyError) key :user_uuid not found
(ecto 3.7.1) lib/ecto/association.ex:754: Ecto.Association.Has.build/3
This is fine if it’s referring to the uuid key in the user map, as I don’t see user_uuid there, it’s just %User{uuid: "1234..."} - or is it referring to user_id in the wallet database? However, why should the build_assoc function expect that and not function as is given the Schema implementation and how can I override it, or set up my schemas and/or own Schema implementation and/or migration correctly?
Thanks for reading this far!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 9- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
krasenyp
The problem is in your
walletsschema. You’ve defined that each wallet belongs to anuser_idbut it should be justuser.phoebe
Thanks @krasenyp - I changed it as you say but the error message still is the same. I think this is because it is the
:foreign_keyparameter for thebelongs_tomacro, but what I do not fully understand is why is this not already captured in the implementation of UUIDs inMyApp.Schema? I also changed it tobelongs_to :user_uuidin thewalletschema. This now gets past the error message. However, in the docs forbelongs_tothe macro also adds the suffix_idto the parameter for the:foreign_keyand this is now what I see after runningSo, there is something unexpected going on with the
user_uuid_idfield - I expected this field to be populated, and notuser_uuid.And when I try to insert this in the database with
Repo.insert(wallet), I get a new error message about invaliduser_uuidfield in the changeset.This kind of makes sense, that should not be there as the valid foreign key should be
user_uuid_idif I read the docs correctly? Am I missing something else that’s obvious? Thankssiddhant3030
I think in your migration primary key should be false and add a new field for uuid and put primary key true. Also in your schema change this
belongs_to :user_id, MyApp.Users.User, references: :uuid, type: :binary_idto this
belongs_to :user, MyApp.Users.UserAnd then you can pass
user_idin the changeset.phoebe
Thanks @siddhant3030 , I forgot to add that I already have in my
config.exs:so
uuid’s are being correctly generated as primary keys in thewalletandusertables.al2o3cr
The errors you are getting suggest that you have a column named
user_uuidon thewalletstable. You’ll need to tell thebelongs_to/has_manymachinery about that:phoebe
Thanks @al2o3cr ! This now works when I also changed my migration to
This raises the question of what these statements actually do in
MyApp.Schemaand config ofMyApp.Repo. It seems I would be better off being explicit withuuideverywhere?aziz
I wanted to point the things in
. So if you set
MyApp.Schemaout to you yesterday:uuidas the field name for the@primary_key, Ecto will use that as the suffix in reference field names. That’s why you getuser_uuidin your Wallet schema. SeeEcto.Association.association_key/2.@foreign_key_type :binary_idis correct. Maybe@derive {Phoenix.Param, key: :uuid}is too general to be inside the Schema macro. Unless you can override it in individual schemas, but I don’t know if Elixir allows you to do that.aziz
Considering you have the
:migration_primary_keyconfigured, adding a column can/should be much shorter:add :user_uuid, references(:users)Yep, looks like a lot of trouble to have the
Unless maybe you intend to have tables with integer ids?
uuidname/suffix everywhere. I would just go withidand set its type to:binary_id.phoebe
Thanks @aziz ! This is clear now, makes sense, cheers!