Updating association with cast_assoc

I have two tables Users and Companies. User belongs to a Company and a Company has many users.

I have a form, where i can add user to the company which is implemented as a nested form(inputs_for), so in the company’s changeset, I have called cast_assoc

def changeset(company, attrs) do
    company
    |> cast(attrs, [:name, :email])
    |> validate_required([:name, :email])
    |> cast_assoc(:users, with: &User.company_admin_changeset/2)
  end

What I want to do is, when I add a already existing user to a company, it should update the user’s company_id(foreign_key). If the user doesnt exists, just create one.

Looking at my requirement, I am starting to think that it is not possible to do it from cast_assoc. So, I have used transaction

  def create_company(attrs \\ %{}) do
    Repo.transaction(fn ->
      cmp =
        Company.changeset(%Company{}, %{name: attrs["name"], email: attrs["email"]})
        |> Repo.insert!()

      Enum.each(attrs["users"], fn {_, user} ->
        case Accounts.get_user_by_email(user["email"]) do
          nil ->
            User.company_admin_changeset(%User{}, %{email: user["email"], company_id: cmp.id})
            |> Repo.insert!()

          account ->
            account |> Ecto.Changeset.change(company_id: cmp.id) |> Repo.update!()
        end
      end)
    end)
  end

but if it is possible can you tell me how I can do it?

Hello and welcome,

You might want to look at Ecto upsert, which means update or insert.

The example is different (post and tags) but the idea is similar.

4 Likes

Definitely. I did went thru the upsert documentation before but that didnt workout but i went thru it again and it worked now.