У меня есть модель Folder
, которая может иметь «дочерние папки».Каждый раз, когда папка обновляется, дочерняя папка также должна обновляться.Это моя попытка создать рекурсивную функцию обновления:
def update(folder_id, params, context \\ "contracts") do
folder = get(folder_id, context, [:groups, :child_folders])
child_folders = folder.child_folders
case child_folders do
child_folders when length(child_folders) > 0 ->
for child_folder <- child_folders do
Contract.Folder.update(child_folder.id, params)
end
[] ->
params = build_folder_groups_params(params)
folder
|> build_changeset(params)
|> put_assoc_by_params(params, folder.context)
|> Repo.update()
end
end
Дочерние папки обновляются, но я получаю сообщение об ошибке соответствия предложения case, и текущая папка не обновляется.
Редактировать:
Я преобразовал цикл в Enum.reduce
.Он отлично работает для первого набора child_folders
, но не является рекурсивным.Как мне сделать это рекурсивным?
def update(folder_id, params, context \\ "contracts") do
folder = get(folder_id, context, [:groups, child_folders: :groups])
child_folders = folder.child_folders
folder_group_params = Map.delete(params, "name")
multi = Enum.reduce(child_folders, Multi.new, fn child_folder, multi_accumulator ->
new_params =
folder_group_params
|> Map.update("folder_groups", [], fn groups ->
Enum.uniq(groups ++ Enum.map(child_folder.groups, &("#{&1.id}")))
end)
|> build_folder_groups_params
child_folder_changeset =
child_folder
|> build_changeset(new_params)
|> put_assoc_by_params(new_params, child_folder.context)
Multi.update(multi_accumulator, :folder, child_folder_changeset)
end)
Repo.transaction(multi)
params = build_folder_groups_params(params)
folder
|> build_changeset(params)
|> put_assoc_by_params(params, folder.context)
|> Repo.update()
end