tnederlof
Self Referencing many_to_many Updating Associations Issues
EDIT ** The code now works after some help
I started a thread a few days ago with some general questions and since I am now focused and have some running code I thought it would make sense to post fresh with more direct questions.
I have Users which can have friendships and the converse of that is a reverse_friendship using the Friendships table (many_to_many relationships). My attempted code is below but I am having 2 problems.
- how to add the associations with timestamps. If I don’t add timestamps to the table in the Friendship migration the inserts run fine
- put_assoc works (User 1 has User 2 as a friend and User 2 has User 1 as a reverse friend). However when I go to add another I get a warning about on_replace, I think thats because put_assoc is essentially trying to overwrite the entire friends/reverse friends. How can I add friend/reverse_friend associations and have it be additive (Add User 2 then User 3, etc to User 1 as a friend).
User Schema
defmodule App.Users.User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
field :name, :string
field :phone_number, :string
field :username, :string
field :email, :string, null: false
many_to_many :friends, User,
join_through: "friendships",
join_keys: [from_user_id: :id, to_user_id: :id]
many_to_many :reverse_friends, User,
join_through: "friendships",
join_keys: [to_user_id: :id, from_user_id: :id]
timestamps()
end
@doc false
def changeset(user_or_changeset, attrs) do
required_fields = [:username, :name, :email, :phone_number]
user_or_changeset
|> cast(attrs, required_fields)
|> validate_required(required_fields)
end
end
User Migration
defmodule App.Repo.Migrations.CreateUsers do
use Ecto.Migration
def change do
create table(:users) do
add :name, :string, null: false
add :username, :string, null: false
add :email, :string, null: false
add :phone_number, :string, null: false
timestamps()
end
create unique_index(:users, [:username, :email, :phone_number])
end
end
Friendship Schema
defmodule App.Users.Friendship do
use Ecto.Schema
alias App.Users.User
import Ecto.Changeset
@primary_key false
schema "friendships" do
belongs_to :from_user, User
belongs_to :to_user, User
timestamps()
end
end
Friendship Migration
defmodule App.Repo.Migrations.AddCreateFriendshipTable do
use Ecto.Migration
def change do
create table(:friendships, primary_key: false) do
add :from_user_id, references(:users)
add :to_user_id, references(:users)
add :accepted, :boolean, default: false
timestamps()
end
create unique_index(:friendships, [:from_user_id, :to_user_id])
end
end
Users Context Module
defmodule App.Users do
import Ecto.Query, warn: false
alias App.Repo
alias App.Users.User
alias App.Users.Friendship
def add_friend(user, friend_user) do
%Friendship{}
|> change()
|> put_assoc(:from_user, user)
|> put_assoc(:to_user, friend_user)
|> Repo.insert()
end
end
Marked As Solved
fuelen
- You have to define a
Friendshipschema and use it inmany_to_manyassociation instead of direct table name. Timestamps will be added automatically if you useRepo.insertorRepo.insert!, but if you want to useRepo.insert_allthen values for timestamps must be provided manually. -
put_assocmanages the whole collection. InsertFriendshiprecord this way:
def add_friend(user, friend_user) do
%Friendship{}
|> change()
|> put_assoc(:from_user, user)
|> put_assoc(:to_user, friend_user)
|> Repo.insert()
end
*tip: add unique composite index for from_user_id and to_user_id fields.
2
Popular in Questions
What is the proper way to load a module from a file in to IEX?
In the python world, doing something like this pretty standard:
from ....
New
Hello, I get Persian date from my client and convert it to normal calendar like this:
def jalali_string_to_miladi_english_number(persi...
New
Credo is smart enough to check for (something like) this:
assert length(the_list) == 0
with this response:
Checking if an enum is empt...
New
Hello!
Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
Hi there,
I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
Good day to you all.
I have been struggling to get a query involving like and ilike to work.
Can anyone assist me on this, please?
pro...
New
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”:
14:57:30.512 [warn] ...
New
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service.
Currently when I de...
New
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
I am trying to run a deploy with docker and I successfully runned with this command:
docker build -t romenigld/blog-prod .
but when I t...
New
Other popular topics
What is the proper way to load a module from a file in to IEX?
In the python world, doing something like this pretty standard:
from ....
New
Hello!
Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
Hi there,
I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service.
Currently when I de...
New
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this
"1000"
What is the ...
New
I tried installing
elixir 1.11.2
erlang 23.3.4
via asdf in my zsh shell. Enabled the versions locally and globally.
When I list them ...
New
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including.
What is Phoenix LiveV...
New
Hi everyone!
I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New








