Creating two models then associating with validation error

Hi everyone

I have encountered a small issue with my Phoenix code. I have three models, Recipe, Ingredient, and RecipeIngredient. The relationship between them is many to many, and the Recipe and Ingredient are “joined” through RecipeIngredient.

When the validation goes fine for the recipe, everything works fine. However, when there is a validation error with the recipe, the ingredients are inserted, but obviously no association takes place (i.e. no recipe ingredients are created, nor the recipe). I would prefer it if in the event of a validation error no related models were inserted.

The logic for creating the recipe is:

def create_recipe(attrs \\ %{}) do
	change_recipe(%Recipe{}, attrs)
	|> Repo.insert()

And the logic for associating the two models is:

def change_recipe(%Recipe{} = recipe, attrs \\ %{}) do
    Recipe.changeset(recipe, attrs)
    |> Ecto.Changeset.put_assoc(:ingredients, process_ingredients(attrs))

def process_ingredients(params) do
	(params["ingredients"] || [])
	|> remove_empty_strings()

defp get_or_insert_ingredient(ingredient) do
		%Ingredient{ingredient: ingredient},
		on_conflict: [set: [ingredient: ingredient]],
		conflict_target: :ingredient

Ecto multi run may help you achieve something like this

Description from the doc:

The function given to run must return {:ok, value} or {:error, value} as its result. Returning an error will abort any further operations and make the whole multi fail.


Thanks @wolfiton

1 Like

Glad i could help