Nested form with number of children based another model

Been reading through as much of the forums as I can trying to find a similar answer but I might not be searching for the right thing.

I’ve been trying out Phoenix and I’ve got stuck on a form involving 3 models, here’s the scenario: You’re creating a new Survey, this Survey has many Answers and each Answer belongs to a Question. A Survey must have one Answer for each Question and the Questions are pre-seeded into the database.

I’ve added the basics of this to a gist. I could be on completely the wrong track to solve this but what I’ve done so far “works” so far as it shows the right fields for answering each question and can naively save the survey and answer records if you are a good and trustworthy user who won’t tinker with the form in devtools.

My first problem occurs when I try to save with validation errors (simply checking if each submitted answer was not empty) and the view would complain of no preloaded association for question on this line <%= label a, :answer, %>. This makes sense because survey and answer only exist in memory at this point so even though I tried adding Repo.preload(answers: [:question]) it didn’t seem to do anything. What I resorted to was looping through all the submitted answers and modifying the changeset data:

{:error, %Ecto.Changeset{} = changeset} ->
  answers =
    for answer <- changeset.changes.answers do
      question =
        Example.Repo.get!(Example.Question, answer.changes.question_id)

      %{answer | data: %Answer{question: question, question_id:}}

  changeset = %{changeset | changes: %{changeset.changes | answers: answers}}
  render(conn, "new.html", changeset: changeset)

This satisfies the view rendering but it relies on the user submitting the right number of questions (i.e. not opening up dev tools and deleting a few fields before hitting submit) and honestly doesn’t seem right but it was a start.

The place I want to put all this code is in the Example.Surveys context module but I tried building the answer structs in Example.Surveys.create_survey/1 and it seemed to all get wiped out.

Any advice on this one?

Have a look at Ecto.Multi and here Also use context for a good readability and logic from here