Update Ecto association in Phoenix controller

I have a small Phoenix app that handles user registration.

Each user belongs to a Sector, and each Sector has many users. The schemas are defined as:

schema "users" do
   belongs_to :sector, MyApp.Sector
end

schema "sectors" do
   has_many :users, MyApp.User
end

In my Phoenix controller, I do some validations and load all the sectors, building a User association, like this:

sector =
  Repo.get!(Sector, user_params["sector_id"])
  |> Repo.preload(:users)

user = Ecto.build_assoc(sector, :users)
changeset = User.changeset(user, user_params)

I really don’t know if that’s the most idiomatic way, but it worked. Users are inserted belonging to the specified Sector.

The problem is when I try to update it. In traditional SQL, this means changing the sector_id from the User. I have tried the following:

user = Repo.get!(User, id) |> Repo.preload(:sector)
changeset = User.changeset(user, user_params)
changeset = 
  Ecto.Changeset.put_assoc(changeset, :sector, Repo.get!(params["sector_id"]))

or even:

user = Repo.get!(User, id) |> Repo.preload(:sector)
user = %{ user | sector: Repo.get!(Sector, params["sector_id"])
changeset = User.changeset(user, user_params)

But the sector that came from params is ignored in the update.
What am I doing wrong?

Thanks!

I’m having some trouble understanding what you really want to do but I’m going to give it a try:

You’ve got a Users table with a Foreign Key sector_id that references the ID’s in the Sectors table, right?

If you want to update the sector of a given user you may do so:

user      = Repo.get!(User, id)
changeset = User.changeset(user, %{"sector_id" => new_id})
Repo.update!(changeset)

Yes, my User has a sector_id. So, I need to update that? And that’s that? I’ll try it today, and post the results here.

Sometimes, we ignore the simple, when we shouldn’t. It worked! Thank you!

For people struggling with this in the future:
make sure to have :sector_id present in the list in function changeset/2 (the second argument of the cast function in pipeline inside).