在进入数据库之前转换变更集 属性

Transform a changeset property before it goes into the database

我在 Elixir 表单中添加了一个 textarea,并将该值设置为 string 并将字符串放入 jsonb 类型的数据库元数据列中. textarea 中的字符串我希望按换行符拆分并存储 stringsarray 而不是一个大字符串。

我已将类型更改如下。

field :names, {:array, :string} 

但是我不确定如何使用 Ecto 拦截这些数据并在它进入数据库之前拆分它。

我看过:

看来我可以在schema中添加一个validation函数,这是我的尝试。

def changeset(schema, params \ %{}) do
    schema
    |> cast(params, @required, @optional)
    |> validate_name()
end

defp validate_names(changeset) do
    # fetch_field(changeset, :names)
    # Map.put(changeset, :names, String.split(:names, "\r\n"))
end

如何更改 Elixir 对象中一个 属性 的值?

更新:

person_metadata.ex

defmodule DB.PersonMetadata do
  use DB.Schema

  embedded_schema do
    field :names, :string
  end

  @required ~w()
  @optional ~w(names)

  def changeset(schema, params \ %{}) do
    schema
    |> cast(params, @required, @optional)
    |> validate_names()
  end

  defp validate_names(changeset) do
    case get_field(changeset, :names) do
      # Don't do anything if names don't exist
      nil ->
        changeset

      # Update names if they do exist
      names ->
        new_names = String.split(names, "\n")
        put_change(changeset, :names, new_names)
    end
  end

  def types, do: @types
end

试试这个:

defp validate_names(changeset) do
  case get_change(changeset, :names) do
    # Update name if it's a string
    names when is_binary(names) ->
      new_names = String.split(names, "\r\n")
      put_change(changeset, :names, new_names)

    # Don't do anything if nil or already an array
    _other ->
      changeset
  end
end

似乎整个自定义函数现在(从什么时候开始?)被替换为 Ecto.Changeset.update_change/3

 |> update_change(:names, fn
     nil -> nil # or preferably []?
     names -> String.split(names, ~r{\r?\n})
    end)

或风格问题

 |> update_change(:names, &my_name_splitter/1)