John Sheppard
John Sheppard

Reputation: 33

Elixir Ecto: Casting multiple belongs_to relationship in a schema goes wrong

First of all: I have a schema players and a schema matches and I want to establish belong_to, has_many relationship between them in phoenix 1.6. What I have tried:

defmodule TennisPhx.Matches.Match do
  use Ecto.Schema
  import Ecto.Changeset
  alias TennisPhx.Participants.Player

  schema "matches" do


    has_many :first_players, Player, foreign_key: :first_player_key_id   <------
    has_many :second_players, Player, foreign_key: :second_player_key_id  <-------

# other not relevant fields 


    timestamps()
  end

  @doc false
  def changeset(match, attrs) do
    match
    |> cast(attrs, [:tour_id, :first_player, :second_player, :starting_datetime, :location_id, :phase_id, :status_id, :player_unit_id])
    |> validate_required([:tour_id, :location_id, :phase_id, :player_unit_id])
  end
end
defmodule TennisPhx.Participants.Player do
  use Ecto.Schema
  import Ecto.Changeset

  alias TennisPhx.Events.Tour
  alias TennisPhx.Matches.Match

  schema "players" do
# other fields

    belongs_to :first_players, Match, foreign_key: :first_player_key_id
    belongs_to :second_players, Match, foreign_key: :second_player_key_id


    timestamps()

  end

  @doc false
  def changeset(player, attrs) do
    player
    |> cast(attrs, [:name, :nickname, :info, :birthdate])
    |> validate_required([:name])
  end
end

My "assign_match" function in a context:

  def assign_match(%Tour{} = tour, first_player, second_player, day, month, year, location, phase, unit) do
    tt = tour.id

    %Match{}
    |> Match.changeset(%{tour_id: tour.id, first_player: first_player, second_player: second_player, location_id: location, phase_id: phase, player_unit_id: unit})
    |> Repo.insert()

  end

And the migration:

  def change do
    alter table("matches") do
      add(:first_player, references(:players, on_delete: :delete_all))
      add(:second_player, references(:players, on_delete: :delete_all))
    end
  end

What error I get:

unknown field `:first_player` given to cast. Either the field does not exist or it is a :through association (which are read-only). The known fields are: :first_players, :id, :inserted_at, :location, :location_id, :phase, :phase_id, :player_unit, :player_unit_id, :score, :second_players, :starting_datetime, :status, :status_id, :tour, :tour_id, :updated_at

Why? We can clearly see that the field in the migration is first_player, singular. When renaming columns to plural, first_players, second_players I get this:

[error] GenServer #PID<0.609.0> terminating
** (RuntimeError) casting assocs with cast/4 for :first_players field is not supported, use cast_assoc/3 instead

What I am doing wrong here? Can't figure it out..

I have followed this article for the relations and for multiple_belongs_to this and this

Upvotes: 1

Views: 794

Answers (1)

Jan
Jan

Reputation: 965

In the migration, first_player is singular. In the Match schema, first_players is plural. These don’t match.

As mentioned in the second error message, you need to use cast_assoc/3 instead of cast/4 in your Match.changeset function. See documentation here for example usage: https://hexdocs.pm/ecto/Ecto.Changeset.html#cast_assoc/3

Upvotes: 1

Related Questions