Ecto Changeset example of updating updating associations

Hello, I have a question on proper working with forms and associations.

I have a form to build a search query. Among the fields there are two belongs_to associations - client and city, which are selected from a select. They can freely be updated later. The only validation is that client must be associated with the current user.

I have a simple select in the form for client_id and city_id:

<div>
  <%= label f, :client_id, "Client" %>
  <%= select f, :client_id, @client_options %>
  <%= error_tag f, :client_id %>
</div>

Then in form I have to take the client based on client_id from params and put it into params like this

defp add_client_param(query_params, socket) do
  case query_params["client_id"] do
    nil -> query_params
    client_id ->
      Map.put(
        query_params,
        "client",
        Enum.find(socket.assigns.clients, & &1.id == client_id)
      )
  end
end

It goes to a simple update function in a context:

def update_query(%Query{} = query, attrs) do
  query
  |> Query.changeset(attrs)
  |> Repo.update()
end

That sends it into changeset in the model:

def changeset(query, attrs) do
  changeset =
    query
    |> cast(attrs, [])
    
  case attrs[:client] do
    nil -> changeset
    client ->
      changeset
        |> put_assoc(:client, attrs[:client])
        |> validate_client()
  end
end

Since I can’t just pass client to cast - I pass it to put_assoc. But if I do update_query generic - caller may not want to update client or other references, so I have to do a case for each reference that caller may omit instead of doing something like cast([:client]).

Is it the proper way to do it? Because I strongly feel that I’m missing something.

Are there any good examples doing simple things like this in a “recommended” way?