The after_save
function isn’t getting called because its arguments don’t match. Let’s walk through how that happens.
We’ll start by regrouping a little; a common idiom in Elixir is to make a function that does something to every element of a list by looping with a function that does something to one element:
def create_files(files \\ [], after_save \\ &{:ok, &1}) do
allFiles =
for file <- files do
create_file(file, after_save)
end
IO.inspect(allFiles)
{:ok, files}
end
defp create_file(file, after_save) do
%File{}
|> File.changeset(file)
|> after_save(after_save)
|> Repo.insert()
end
Now split apart the pipe in create_file
:
defp create_file(file, after_save) do
changeset = File.changeset(%File{}, file)
changeset_after_callback = after_save(changeset, after_save)
Repo.insert(changeset_after_callback)
end
Shapes:
-
changeset
is anEcto.Changeset
struct -
the first head of
after_save
does not match, so the second runs - thuschangeset_after_callback
is the sameEcto.Changeset
struct aschangeset
. -
Repo.insert
can return either{:ok, %File{}}
or{:error, %Ecto.Changeset{}}
Based on the shape that after_save
expects in that first head, I suspect you want to move the after_save
call to… after the save, done by Repo.insert
:
defp create_file(file, after_save) do
changeset = File.changeset(%File{}, file)
insert_result = Repo.insert(changeset)
after_save(insert_result, after_save)
end
Shapes in this version:
-
changeset
is anEcto.Changeset
struct -
Repo.insert
can return either{:ok, %File{}}
or{:error, %Ecto.Changeset{}}
forinsert_result
-
if the insert succeeded, the first head of
after_save
will match and call theafter_save
callback. Otherwise, the error will be returned as-is via the second head ofafter_save
.
And then the code can be smooshed back together into a pipe:
defp create_file(file, after_save) do
%File{}
|> File.changeset(file)
|> Repo.insert()
|> after_save(after_save)
end
Edit: by the way, did you mean allFiles
in the return value of create_files
?
{:ok, files}
end