Invalid association warning

I’m new to creating Database with ecto.

I created migration files and schema filed in a phoenix project.

These are my migration files and schema files.

migration files

defmodule DbServer.Repo.Migrations.CreateGames do
  use Ecto.Migration

  def change do
    create table(:games) do
      add :game_name, :string

      timestamps()
    end
  end
end
defmodule DbServer.Repo.Migrations.CreateUsers do
  use Ecto.Migration

  def change do
    create table(:users, primary_key: false) do
      add :user_id, :string, primary_key: true
      add :user_name, :string
      add :user_email, :string
      add :user_password, :string
      add :user_gender, :integer
      add :user_bio, :string
      add :user_birthday, :utc_datetime
      add :user_hosting_experience, :integer
      add :following_games_id, references(:games)

      timestamps()
    end
  end
end

schema files

defmodule DbServer.Schema.Game do
  use DbServer.AroundSchema
  
  schema "games" do
    field :game_name, :string

    many_to_many :users, User, join_through: "users"
    has_one :tournaments_game, Tournament

    timestamps()
  end

  def changeset(game, params \\ :empty) do
    game
    |> cast(params, [:game_name])
    |> validate_required(:game_name)
    |> unique_constraint(:game_name, message: "The game already exists.")
  end
end
defmodule DbServer.Schema.User do
  use DbServer.AroundSchema

  alias Comeonin.Bcrypt

  @primary_key {:user_id, :string, []}

  schema "users" do
    field :user_name, :string
    field :user_email, :string
    field :user_password, :string
    field :user_gender, :integer
    field :user_bio, :string
    field :user_birthday, :utc_datetime
    field :user_hosting_experience, :integer, default: 0

    #belongs_to :following_games, DbServer.Schema.Game

    has_one :tournament, Tournament

    timestamps()
  end

  @user_name_regex ~r"^[a-z0-9_\-\.]+$"
  @email_regex ~r/@/

  @doc false
  def changeset(user, params \\ :empty) do
    user
    |> cast(params, [:user_id, :user_name, :user_email, :user_password, :user_gender, :user_bio, :user_birthday, :user_hosting_experience])
    |> validate_required([:user_id, :user_name, :user_email, :user_password, :user_gender, :user_bio, :user_birthday, :user_hosting_experience])
    |> unique_constraint(:user_id, message: "The id has been already taken.")
    |> validate_length(:user_name, min: 3)
    |> validate_format(:user_name, @user_name_regex)
    |> unique_constraint(:user_email, message: "The email already exists.")
    |> validate_format(:user_email, @email_regex, message: "Invalid format.")
    |> validate_length(:user_password, min: 8, max: 20)
    |> validate_format(:user_password, ~r/[A-Z]+/, message: "Password must contain an upper-case letter.")
    |> validate_format(:user_password, ~r/[a-z]+/, message: "Password must contain a lower-case letter.")
    |> validate_format(:user_password, ~r/[0-9]+/, message: "Password must contain a number.")
    |> validate_format(:user_password, ~r/[#\!\?&@\$%^&*\(\)]+/, message: "Password must contain a symbol.")
    |> validate_confirmation(:user_password, message: "Does not match password.")
    |> put_pass_hash()
    |> validate_length(:user_bio, max: 125)
  end

  defp put_pass_hash(%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset) do
    change(changeset, user_password: Bcrypt.hashpwsalt(password))
  end
  defp put_pass_hash(changeset), do: changeset
end

In the unit tests, a warning message appeard.

warning: invalid association `tournament` in schema DbServer.Schema.User: associated schema DbServer.Schema.Tournament does not have field `user_user_id`
  lib/db_server/schema/user.ex:1: DbServer.Schema.User (module)

.........

Finished in 0.1 seconds
9 tests, 0 failures

How can I resolve the warning?

Can I ask why you are prefixing all of your column names with user_ ? They’re already on a table named users. users.user_whatever just seems repetitive.

Setting that aside, the error explains the reason. You say that has_one :tournaments_game, Tournament in your User schema, this requires that the tournaments table has a column that points to the users table. By default that column would be named #{schema_name}_#{primary_key} which for you is user_user_id.

1 Like

Anyway, I’m changing my column names!

Do I have to make a column like user_user_id?
I will change the column names though.

Thanks!

The Tournaments table needs a user_id column if you want it to belong to a user.

2 Likes

Thank you!