Elixir 中的自定义类型

Custom Types in Elixir

我有一个玩具项目可以帮助我学习 Elixir/Phoenix。

我正在从 csv 导入一些数据,如果根据我的变更集它们是有效的,我想将这些记录插入到数据库中。

我的问题是,有时通常包含整数的列之一会有 "n/a"。这会导致变更集无效,而它本应如此。

我不确定 Elixir 处理此问题的标准方法是什么。

在这些情况下,我只想将 "n/a" 转换为 0。

您通常会为此编写自定义类型来执行该转换吗?

https://hexdocs.pm/ecto/Ecto.Type.html

在 Rails 中,我可能会使用自定义 setter 或 before_save 或其他方式在模型上解决此问题。

在发送到 cast 进行验证之前,我会通过 "fixing" params 在模型的 changeset 函数中执行此操作。

带有 :count 整数字段的示例模型:

def changeset(struct, params \ %{}) do
  struct
  |> cast(fix_params(params), [:count])
  |> validate_required([:count])
end

defp fix_params(%{count: "n/a"} = params), do: %{params | count: 0}
defp fix_params(params), do: params

演示:

iex(1)> Counter.changeset(%Counter{}, %{count: 123})
#Ecto.Changeset<action: nil, changes: %{count: 123}, errors: [],
 data: #MyApp.Counter<>, valid?: true>
iex(2)> Counter.changeset(%Counter{}, %{count: "n/a"})
#Ecto.Changeset<action: nil, changes: %{count: 0}, errors: [],
 data: #MyApp.Counter<>, valid?: true>
iex(3)> Counter.changeset(%Counter{}, %{count: "foo"})
#Ecto.Changeset<action: nil, changes: %{},
 errors: [count: {"is invalid", [type: :integer]}], data: #MyApp.Counter<>,
 valid?: false>

如果你想任何非整数值转换为0,你可以这样做:

defp fix_params(%{count: count} = params) when not is_integer(count), do: %{params | count: 0}
defp fix_params(params), do: params

演示:

iex(1)> Counter.changeset(%Counter{}, %{count: "foo"})
#Ecto.Changeset<action: nil, changes: %{count: 0}, errors: [],
 data: #MyApp.Counter<>, valid?: true>