Trying to understand build_assoc

in user.ex

  schema "users" do
    field :email, :string
    field :first_name, :string
    field :last_name, :string

    has_many :phonebooks, Phonebook
    has_many :phonenumbers, Phonenumber
    has_many :orders, Order
    has_many :people, Person

    timestamps()
  end

in person.ex

  schema "people" do
    field :name, :string
    field :phone_number, :string
    field :email, :string
    belongs_to :phonebook, Phonebook
    belongs_to :user, User
    
    timestamps()
  end

in contact.ex

  def create_person(phonebook, user, attrs \\ %{}) do
    build_assoc(phonebook, :people) 
    |> Person.changeset(attrs)
    |> Repo.insert()
  end

in contact.ex I did “build_assoc” and also I want to do

build_assoc(user, :people)

to build assoc with user in people table.
What is the best way?

3 Likes

Assuming you are creating a person with a phonebook and user al ready saved in your database, you can refactor you code as follows to add both associations in one line:

def create_person(phonebook, user, attrs \\ %{}) do
  %Person{phonebook: phonebook.id, user: user.id}
  |> Person.changeset(attrs)
  |> Repo.insert()
end

Under the hood build_assoc adds the corresponding id to the association struct.

I’d try

def create_person(phonebook, user, attrs \\ %{}) do
  build_assoc(phonebook, :people) 
  |> Person.changeset(attrs)
  |> Ecto.Changeset.put_assoc(:user, user)
  |> Repo.insert()
end
1 Like

I ran into something similar here’s my approach.

def create_person(phonebook, user, attrs \\ %{}) do
  [phonebook, user]
  |> Enum.reduce(%Person{}, fn (link_to, person) ->
        build_assoc(link_to, :people, person) 
      end)
  |> Repo.insert()
end