Phoenix form error after unique constraint

hi guys,

Got this error, when i put a unique constraint on user_id
and html doesn’t have user_id as input.
i set it in controller => Users.create_user_preference(current_user, preference_params)

def create_user_preference(user, attrs \\ %{}) do
    user
    |> Ecto.build_assoc(:preference)
    |> Preference.changeset(attrs)
    |> Repo.insert()
  end

def changeset(preference, attrs) do
    preference
    |> cast(attrs, [:age, :height, :religion_id, :height, :body_type,
                    :education_id, :occupation_id,  :caste_id, :user_id])
    |> validate_required([:religion_id, :user_id])
    |> unique_constraint(:user_id, name: :preferences_user_id_index)
  end

Getting the following error,
lists in Phoenix.HTML and templates may only contain integers representing bytes, binaries or other lists, got invalid entry: {:user_id, {“has already been taken”, [constraint: :unique, constraint_name: “preferences_user_id_index”]}}

How to resolve this fellows? thank you folks.

If you are running into this type of error, I would assume that we have some issues with your backend code and not the form.

We could do one of two things in my mind. We should be passing the existing preference to the changeset if it exists, or we should change the insert into an upsert (insert or update) so that we can update the existing row in the database.

Take a look at the Ecto.Repo documentation on insert, the two options you are going to want to look at are :on_conflict and :conflict_target if you are considering the upsert option.

1 Like

Yes @tomciopp, I thought the same. To resolve this i took a different approach. I am a rails guy so i went with find_or_initialize method along with elixir’s pattern matching and assigned action to create or update based on presence of the object id. (preference.id)

  def get_user_preference(user_id), do: Repo.get_by(Preference, user_id: user_id)

  def find_or_initialize_user_preference(user) do
    case get_user_preference(user.id) do
      nil ->
        user |> Ecto.build_assoc(:preference)
      preference ->
        %Preference{} = preference
    end
  end