Ecto Changeset добавляет функциональность для предупреждений

Я создал форк репозитория ecto, чтобы расширить модуль Ecto.Changeset с возможностью добавления предупреждений в набор изменений. Я хотел иметь функцию add_warnings/4, которая добавляет предупреждение в набор изменений в виде простого списка предупреждений с этой структурой warnings: [{atom, {String.t, Keyword.t}}], похожей на errors. Разница между поведением warnings и errors заключается в том, что при возникновении ошибки данные не сохраняются, а при возникновении предупреждения данные сохраняются.

Ecto.Changeset структура расширена ключами warnings и warningless?:

defstruct valid?: false, warningless?: false, data: nil, params: nil, changes: %{}, repo: nil,
        errors: [], warnings: [], validations: [], required: [], prepare: [],
        constraints: [], filters: %{}, action: nil, types: nil,
        empty_values: @empty_values

Настроены функции экто для литья, изменения, обработки и т. Д. Добавлена ​​функция add_warnings/4:

@spec add_warning(t, atom, String.t, Keyword.t) :: t
def add_warning(%{warnings: warnings} = changeset, key, message, keys \\ []) when is_binary(message) do
  %{changeset | warnings: [{key, {message, keys}}|warnings], warningless?: false}
end 

В результате я получаю changeset с ожидаемыми ключами:

#Ecto.Changeset<action: nil, changes: %{}, data: #Company.Booking<>, errors: [],
valid?: true, warnings: [], warningless?: true>

Когда я вношу изменение с ошибкой и предупреждением, я получаю:

#Ecto.Changeset<action: nil,
changes: %{pickup_address: #Ecto.Changeset<action: :update,
changes: %{street_name: nil}, data: #Company.Address<>,
errors: [street_name: {"can't be blank", [validation: :required]}],
valid?: false,
warnings: [phone_number: {"This phone number is not common in Netherlands",
  []}], warningless?: false>}, data: #Company.Booking<>, errors: [],
valid?: false, warnings: [], warningless?: true>

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

#Ecto.Changeset<action: nil,
changes: %{pickup_address: #Ecto.Changeset<action: :update,
changes: %{street_name: "sss"}, data: #Company.Address<>, errors: [],
valid?: true,
warnings: [phone_number: {"This phone number is not common in Netherlands",
  []}], warningless?: false>}, data: #Company.Booking<>, errors: [],
valid?: true, warnings: [], warningless?: true>

Все как положено. Если я не вношу никаких изменений в форму, я все равно получаю предупреждение о номере телефона, но я получаю:

#Ecto.Changeset<action: nil, changes: %{}, data: #Company.Booking<>,    errors: [],
valid?: true, warnings: [], warningless?: true>

Я получил набор изменений без каких-либо предупреждений, поскольку в наборе изменений нет ключа changes, потому что данные не изменились.

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


person Adam Skołuda    schedule 23.06.2017    source источник
comment
Вы не показываете никаких функций набора изменений. Предположительно, вы захотите использовать Ecto.Changeset.get_field/3 вместо _ 2_ при добавлении предупреждения. Впрочем, какова в этом цель? Если вы захотите сохранить данные при предупреждении, вы потеряете набор изменений и не сможете показать пользователю сообщение.   -  person Justin Wood    schedule 23.06.2017


Ответы (1)


Вам следует подумать о том, чтобы предварительно заполнить предупреждения в самом начале каждой changeset функции, которую вы создадите - поскольку вы не можете использовать plug там, вы можете написать макрос, который будет обрабатывать эту логику за вас, рекомендуется __using__, поэтому будет довольно легко отличить вашу логику от логики Ecto по умолчанию.

Ваша проверка не должна добавлять предупреждения в список предупреждений, но вы должны реализовать ее по-другому - если с полем все в порядке, вы удалите уже существующие предупреждения из этого списка. Таким образом, вы будете уверены, что ваш набор изменений в порядке, когда он warningless, потому что он удалил все предупреждения из этого списка и отлично подойдет для пустых изменений в наборе изменений.

person PatNowak    schedule 26.10.2017