Как мне объединить ошибки ревизий? - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь объединить ошибки набора изменений.

У меня есть схема Учреждения, которая принадлежит пользовательской схеме.Некоторые поля являются обязательными для каждого, но ответ об ошибке выглядит следующим образом:

{
    "errors": {
        "user": {
            "password_confirmation": [
                "The password confirmation does not match the password."
            ],
            "password": [
                "This field is required."
            ],
            "name": [
                "This field is required."
            ]
        },
        "institution": {
            "web_address": [
                "is required."
            ]
        },

    }
}

Как мне объединить эти объекты ошибок в один?

Моя вставка выглядит так:

 user_changeset =
      User.normal_user_changeset(%User{}, %{
        :email => Map.get(attrs, "email"),
        :password => Map.get(attrs, "password"),
        :password_confirmation => Map.get(attrs, "password_confirmation"),
        :name => Map.get(attrs, "name"),
        :postcode => Map.get(attrs, "postcode"),
        :dob => Map.get(attrs, "dob")
      })

    institution =
      %Institution{}
      |> Institution.changeset(%{
        :web_address => Map.get(attrs, "web_address"),
        :person_responsible => Map.get(attrs, "person_responsible"),
        :annual_turnover => Map.get(attrs, "annual_turnover")
      })
      |> Ecto.Changeset.put_assoc(:user, user_changeset)
      |> Repo.insert()

Я хотел бы, чтобы ответ об ошибке был:

 {
        "errors": {
                "password_confirmation": [
                    "The password confirmation does not match the password."
                ],
                "password": [
                    "This field is required."
                ],
                "name": [
                    "This field is required."
                ]
                "web_address": [
                    "is required."
                ]
        }
    }

У меня есть эта функция в моем резервном контроллере (здесь по умолчанию):

  def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
    conn
    |> put_status(:unprocessable_entity)
    |> render(SfiWeb.ChangesetView, "error.json", changeset: changeset)
  end

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Вы можете получить значения поля errors и объединить их все, используя Enum.reduce/3:

map = Jason.decode! """
{
    "errors": {
        "user": {
            "password_confirmation": [
                "The password confirmation does not match the password."
            ],
            "password": [
                "This field is required."
            ],
            "name": [
                "This field is required."
            ]
        },
        "institution": {
            "web_address": [
                "is required."
            ]
        }
    }
}
"""

Map.update!(map, "errors", fn errors ->
  errors |> Map.values() |> Enum.reduce(%{}, &Map.merge/2)
end)
|> IO.inspect

Вывод:

%{
  "errors" => %{
    "name" => ["This field is required."],
    "password" => ["This field is required."],
    "password_confirmation" => ["The password confirmation does not match the password."],
    "web_address" => ["is required."]
  }
}
0 голосов
/ 16 октября 2018

errors - это только одно из значений в %Ecto.Changeset{} struct.

Тем не менее, всегда можно изменить %Ecto.Changeset{} для предоставления пользовательских errors:

def fix_errors(%Ecto.Changeset{errors: errors} = ch) do
  %Ecto.Changeset{ch | errors: errors ++ [:my_custom_error]}
end

Вам просто нужно переназначить свой ввод, используя функцию, подобную приведенной выше, и вставить результат в цепочку ревизий:

institution =
  %Institution{}
  |> ...
  |> Ecto.Changeset.put_assoc(:user, user_changeset)
  |> fix_errors() # see above 
  |> Repo.insert()

Независимо от того, предоставили ли вы действительные термины Elixir для errors ранееи после я мог показать, как выполнить само преобразование.Например:

errors = %{
  institution: %{web_address: ["is required"]},
  user: %{
    name: ["is required."],
    password: ["is required."],
    password_confirmation: ["no match"]
  }
}

Может быть сплющен как:

input
|> Enum.map(fn {_, v} -> v end)
|> Enum.reduce(&Map.merge/2)
#⇒ %{
#   name: ["is required."],
#   password: ["is required."],
#   password_confirmation: ["no match"],
#   web_address: ["is required"]
# }
...