Hello!
I have a Player schema and each player can have multiple heroes (one-to-many) when trying to insert a Player with associated Heroes in my tests, they fail. The weird thing is that when I run my app iex -S mix
and try to insert a Player with Heroes it works! But not in the tests
1) This is my Heroe schema:
defmodule Iclash.Repo.Schemas.Heroe do
use Ecto.Schema
import Ecto.Changeset
@optional_fields [:player_tag, :inserted_at, :updated_at]
@required_fields [:name, :level, :max_level, :village]
@primary_key false
schema "heroes" do
field :name, :string, primary_key: true
field :level, :integer, primary_key: true
field :max_level, :integer
field :village, Village
belongs_to :player, Player,
foreign_key: :player_tag,
primary_key: true,
type: :string,
references: :tag,
on_replace: :update
timestamps(type: :utc_datetime_usec)
end
def changeset(%__MODULE__{} = heroe, attrs \\ %{}) do
heroe
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
2) This is my Heroe migration:
defmodule Iclash.Repo.Migrations.AddHeroesTable do
use Ecto.Migration
def change do
create table(:heroes, primary_key: false) do
add :player_tag,
references(:players,
column: :tag,
type: :string,
on_delete: :delete_all,
on_update: :update_all
),
primary_key: true
add :name, :string, primary_key: true
add :level, :integer, primary_key: true
add :max_level, :integer, null: false
add :village, :string, null: false
timestamps(type: :utc_datetime_usec)
end
end
end
3) This is the test I try to run:
setup do
now = ~U[2025-08-08 12:00:00.000000Z]
five_minutes_later = DateTime.add(now, 5, :minute)
heroes_map = [
%{
player_tag: "#P1",
name: "HERO 1",
level: 100,
max_level: 100,
village: "home",
inserted_at: now,
updated_at: now
},
%{
player_tag: "#P1",
name: "HERO 2",
level: 100,
max_level: 100,
village: "home",
inserted_at: five_minutes_later,
updated_at: five_minutes_later
}
]
{:ok, player} =
%{
tag: "#P1",
name: "PLAYER 1",
trophies: 100,
town_hall_level: 17,
best_trophies: 100,
attack_wins: 10,
defense_wins: 10,
role: "admin",
war_preference: "in",
heroes: heroes_map,
inserted_at: now,
updated_at: now
}
|> PlayerSchema.to_struct()
%{now: now, player: player}
end
describe "get_player/1" do
test "Gets a player and return player struct", %{player: player} do
{:ok, inserted_player} = Repo.insert(player) # <--- This is the line of the error.
...
end
end
end
4) This is the error im getting:
1) test get_player/1 Gets a player and return player struct (Iclash.DomainTypes.PlayerTest)
test/iclash/domain_types/player_test.exs:53
** (Postgrex.Error) ERROR 42703 (undefined_column) column "player_tag" of relation "heroes" does not exist
query: INSERT INTO "heroes" ("name","level","player_tag","inserted_at","updated_at","max_level","village") VALUES ($1,$2,$3,$4,$5,$6,$7)
code: {:ok, inserted_player} = Repo.insert(player)
stacktrace:
(ecto_sql 3.12.1) lib/ecto/adapters/sql.ex:1096: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto 3.12.5) lib/ecto/repo/schema.ex:837: Ecto.Repo.Schema.apply/4
(ecto 3.12.5) lib/ecto/repo/schema.ex:416: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
(ecto 3.12.5) lib/ecto/association.ex:948: Ecto.Association.Has.on_repo_change/5
(ecto 3.12.5) lib/ecto/association.ex:648: anonymous fn/8 in Ecto.Association.on_repo_change/7
(elixir 1.17.0) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.12.5) lib/ecto/association.ex:644: Ecto.Association.on_repo_change/7
(elixir 1.17.0) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.12.5) lib/ecto/association.ex:589: Ecto.Association.on_repo_change/4
(ecto 3.12.5) lib/ecto/repo/schema.ex:1021: Ecto.Repo.Schema.process_children/5
(ecto 3.12.5) lib/ecto/repo/schema.ex:1099: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
(ecto_sql 3.12.1) lib/ecto/adapters/sql.ex:1400: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection 2.7.0) lib/db_connection.ex:1756: DBConnection.run_transaction/4
test/iclash/domain_types/player_test.exs:54: (test)