Please, could you help me refine this Ecto changeset manipulation function?

Basically I would like to to automatically create a full name from first and last names provided by a form.

I have something that works but I find it a bit ugly or or too verbose.

Do you think the below function ensure_full_name is fine or would it be possible to make it better or nicer?

PS: I’m using it on changeset for both insert/update operations.

Thanks.

  alias Ecto.Changeset

  defp ensure_full_name(
         %Changeset{valid?: true, changes: %{first_name: first, last_name: last}} = changeset
       ) do
    put_change(changeset, :full_name, "#{first} #{last}")
  end

  defp ensure_full_name(
         %Changeset{valid?: true, changes: %{first_name: first}, data: %{last_name: last}} =
           changeset
       ) do
    put_change(changeset, :full_name, "#{first} #{last}")
  end

  defp ensure_full_name(
         %Changeset{valid?: true, changes: %{last_name: last}, data: %{first_name: first}} =
           changeset
       ) do
    put_change(changeset, :full_name, "#{first} #{last}")
  end

  defp ensure_full_name(changeset), do: changeset

I think you could clean this up a bit using get_field/3.

While get_change/3 only looks at the current changes to retrieve a value, this function looks at the changes and then falls back on the data, finally returning default if no value is available.

https://hexdocs.pm/ecto/Ecto.Changeset.html#get_field/3

1 Like

Thanks I was getting some error with get_field/2 sometimes ago but now I know why. In those cases I where calling the function on a Struct that is not an Ecto changeset. And probably I was not pattern matching either an Ecto changeset in the function params.

Thanks to your suggestion I tried it again and figured out all these things.

Here is the new look of the function:

  defp ensure_full_name(%Changeset{valid?: true, changes: changes} = changeset)
       when changes != %{} do
    first = get_field(changeset, :first_name)
    last = get_field(changeset, :last_name)
    put_change(changeset, :full_name, "#{first} #{last}")
  end

  defp ensure_full_name(changeset), do: changeset
1 Like