benonymus

benonymus

Warning found duplicate primary keys for association/embed in liveview with nested cast_assoc changeset

Hey,

I have a liveview application with a nested changeset.

There is study on top.
This has a cast_assoc for scenarios.
And scenarios has a cast_assoc for scenario_tasks.

I am having a problem on the scenario tasks level.

When I add a 3rd new scenario_task in liveview I am seeing this warning:

[warning] found duplicate primary keys for association/embed :scenario_tasks in Scenario. In case of duplicate IDs, only the last entry with the same ID will be kept. Make sure that all entries in :scenario_tasks have an ID and the IDs are unique between them

I think this is because now in cast there are multiple scenario_tasks with nil for id.

This seems to not cause any problems for add/update, but when I am deleting these entries either all of them go at once, or the last 2 go at once.

I am also not sure if the interaction with the changeset is correct (legacy code).

Add is done like this:

  def handle_add_task(socket, scenario_i) do
    {scenario_index, _rem} = Integer.parse(scenario_i)

    study_changeset = socket.assigns.study_changeset
    scenarios = Ecto.Changeset.get_field(study_changeset, :scenarios, []) || []
    nth_scenario = Enum.at(scenarios, scenario_index)

    updated_tasks = nth_scenario.scenario_tasks ++ [%{title: ""}]

    nth_scenario_with_new_task =
      Ecto.Changeset.change(nth_scenario, %{scenario_tasks: updated_tasks})

    scenarios_with_i_updated =
      List.replace_at(scenarios, scenario_index, nth_scenario_with_new_task)

    updated_study_changeset =
      Ecto.Changeset.put_change(study_changeset, :scenarios, scenarios_with_i_updated)

    {:noreply, assign(socket, study_changeset: updated_study_changeset)}
  end

Remove is done like this:

  def handle_event("remove_task", %{"task" => task_i, "scenario" => scenario_i}, socket) do
    {scenario_index, _rem} = Integer.parse(scenario_i)
    {task_index, _rem} = Integer.parse(task_i)

    study_changeset = socket.assigns.study_changeset

    scenarios = Ecto.Changeset.get_field(study_changeset, :scenarios, []) || []

    nth_scenario = Enum.at(scenarios, scenario_index)

    scenario_tasks = Ecto.Changeset.get_field(nth_scenario, :scenario_tasks, [])

    updated_tasks = List.delete_at(scenario_tasks, task_index)

    nth_scenario_changeset = Ecto.Changeset.change(nth_scenario, %{scenario_tasks: updated_tasks})

    updated_scenarios = List.replace_at(scenarios, scenario_index, nth_scenario_changeset)

    study_changeset = Ecto.Changeset.put_change(study_changeset, :scenarios, updated_scenarios)

    {:noreply, assign(socket, study_changeset: study_changeset)}
  end

My questions would be, is the handling of the changes to the changeset fine this way?
Any ideas how to handle the duplicate primary keys warning?

Thank you

Marked As Solved

benonymus

benonymus

More or less got it sorted, this helped: Warning about duplicated primary keys for new records · Issue #3514 · elixir-ecto/ecto · GitHub
I am changed ti code, to not pass tasks as structs, but always as maps.

Also Liked

al2o3cr

al2o3cr

I’ve encountered this before when doing “add another” kinds of patterns, but I haven’t written the blog post I’ve been promising myself I’d write yet.

The short short version: put_change does not like seeing action: :replace changesets in its input for IDs it already has one for, so filter them out.

This replicates the behavior of changesets in old-school server-side rendering: phoenix_ecto skips them altogether when generating inputs:

https://github.com/phoenixframework/phoenix_ecto/blob/650aa8b32d4ba9ed8bb193c2fd03708629032b8e/lib/phoenix_ecto/html.ex#L168-L173

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
dotdotdotPaul
Okay, I’m having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I’m sure I’...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43806 214
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31307 143
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New

We're in Beta

About us Mission Statement