I am working on a first elixir project and I am struggling quite a lot with the many_to_many association. I have got it sort-of working using the auto-generated link table, however it does not seem to be checking for uniqueness on the link succesfully.
defmodule KevinCadleFantasyGame.Lineup do
use Ecto.Schema
import Ecto.Changeset
alias KevinCadleFantasyGame.{Player, Repo, Lineup}
schema "lineups" do
many_to_many :players, Player,
join_through: "lineup_players", unique: true
timestamps()
end
@doc false
def changeset(lineup, attrs) do
player_ids = if Map.has_key?(attrs, :player_ids), do: attrs.player_ids, else: []
players = Player.by_ids(player_ids)
lineup
|> Repo.preload(:players)
|> cast(attrs, [:id])
|> put_assoc(:players, players)
|> unique_constraint(:players)
|> validate_required([])
end
def create_or_update(params) do
cs = changeset(%Lineup{}, params)
if cs.valid? do
Repo.insert!(cs,
on_conflict: :nothing,
conflict_target: :id
)
else
cs
end
end
end
and the migration:
defmodule KevinCadleFantasyGame.Repo.Migrations.CreateLineups do
use Ecto.Migration
def change do
create table(:lineups) do
timestamps()
end
create table("lineup_players", primary_key: false) do
add :player_id, references(:players)
add :lineup_id, references(:lineups)
end
create unique_index(:lineup_players, [:player_id, :lineup_id])
end
end
With a non-unique link it is giving me a postgres error due to a failure of uniqueness constraint, which is fine, but ideally I’d probably like it to be caught on the changset. What am i doing wrong?
I had tried that, it doesn’t seem to make any difference. With renamed to unique_lineup_players (rather than the previous default of lineup_players_player_id_lineup_id_index), i still get the postgrex error: