Many to many self referencing schema for user following

Hi guys,

I’m trying to build something similar to Twitter where users can follow other users. I’m not sure exactly how to properly create self-referencing schema in this case.

Migrations:

defmodule MyApp.Repo.Migrations.CreateUsers do
  use Ecto.Migration

  def change do
    create table(:users) do
      add :username, :string
    end
  end
end

defmodule MyApp.Repo.Migrations.CreateFollows do
  use Ecto.Migration

  def change do
    create table(:followings) do
      add :follower_id, references(:users, on_delete: :delete_all)
      add :followed_id, references(:users, on_delete: :delete_all)
      timestamps()
    end

    create index(:followings, [:follower_id, :followed_id], unique: true)
  end
end

Schemas:

defmodule MyApp.User do
  use Ecto.Schema

  schema "users" do
    field :username, :string

    ...
  end
end

defmodule MyApp.Follow do
  use Ecto.Schema

  schema "followings" do
    ---
  end
end

Can someone help me write the schemas properly using many_to_many please?

Did you try following this example in the docs? Basically it’s just a normal schema that you pass to the join_through option of many_to_many instead of the table name directly. Although it’s maybe worth noting that you don’t need to use a join schema. Personally I often prefer to avoid dealing with non-intuitive concept names like a “Follow”…

I did check those pages abut I’m not entirely sure which approach even to take as it’s the self-referencing schema.

What part of the self-referencing is causing you problems?

To be honest, I don’t even know… I also don’t like those abstract names, what do you think about a table called “followings” with “user_id” and a “follower_id”?

schema "users" do
    field :name, :string

    many_to_many :users, User, join_through: Followings, join_keys: [user_id: :id, follower_id: :id]
    many_to_many :followers, User, join_through: Followings, join_keys: [follower_id: :id, user_id: :id]
  end
schema "followings" do
    field :user_id, :id
    field :follower_id, :id
  end