How to validate uniqueness of a given embedded field when they don't have ids?


There is a social_networks embedded fields which are mapped to array column in the database. They consists of two properties - name and url and each name name should be unique. For example - there should be only one record with the MeWe name.

Here is how my validator looks like:

def changeset(newsletter_settings, params \\ %{}) do  
 |> cast_embed(
      with: fn item, item_params ->
        social_networks_changeset(item, item_params, Map.get(params, "social_networks"))

here I’m passing social_networks collection so it’ll possible to access other items and see if there are any duplicates.

Now in the params all entries has automatically assigned ids

"social_networks" =>  %{
  "0" => %{"name" => "mewe", "url" => ""}, 
  "1" => %{"name" => "twitter", "url" => ""}, 
  "2" => %{"name" => "mewe", "url" => ""}

Here records 0 and 2 are invalid because they’re pointing to the same social network.

Question is how to check which exactly records share the same name? I would imagine that having access to the “ids” assigned in params will be enough, but can’t see how to do it within validate_change

    defp social_networks_changeset(item, params, collection) do
    |> cast(params, @social_network_required_fields)
    |> validate_change(changeset, :name, fn :name, name ->
      # What exactly record is this? 
      # Is this a first duplicate? 

A simple workaround can be temporarily assigning the id field and clean it up later.

1 Like