How to deal validation with list of entities to insert

Hi,

I’m trying to insert a list of entities my using Enum.each but I have problem with how to deal with it if some validation fails.

I have external parameters from frontend:

[%{"option_id" => 2, "poll_id" => 1}, %{"option_id" => 3, "poll_id" => 1}]

Then in my context

    Enum.each(attrs, fn params ->
      %Vote{}
        |> Vote.changeset(params)
        |> Repo.insert()
    end)

When I look at the docs, Enum.each returns an :ok atom but what I want is to match the return with my controller.

  def cast_vote(conn, %{"vote" => vote_params}) do
    with  {:ok, _vote} <- Polls.cast_vote(vote_params) do
      send_resp(conn, :no_content, "")
    end
  end

I also want to return a 400 bad request when a validation error occurs in one of the elements of the list.

Put validation logic in your Vote.changeset/2. Study https://hexdocs.pm/ecto/data-mapping-and-validation.html thoroughly.

As to the return of 400s, try using the fallback controllers feature in Phoenix https://elixircasts.io/simplifying-phoenix-controllers-with-action_fallback this will be cleaner than pattern matching all the time

First step: Enum.each is only useful when you don’t care about the results - switching to Enum.map will get you a list of {:ok, %Vote{}} | {:error, changeset} tuples.

From that, you can parse out if there were any errors.

Also consider what you want to happen to Vote records that are successfully inserted in the same request with a Vote that gets an error; should they be rolled back? Consider using a Repo.transaction block or an Ecto.Multi to coordinate saving multiple rows.