Функция рекурсивного обновления в контроллере Phoenix - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть модель 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

1 Ответ

0 голосов
/ 18 сентября 2018

В вашем предложении case у вас есть только две возможные ситуации: либо список пуст, либо содержит элементы, поэтому вы можете изменить условие на

case length(child_folders) do
   0 -> params = build_folder_groups_params(params)  
        folder
         |> build_changeset(params)
         |> put_assoc_by_params(params, folder.context)
         |> Repo.update()
   _ -> child_folders 
         |> Enum.Each(fn child_folder -> Contract.Folder.update(child_folder.id, params) end)
 end
...