如何验证嵌套地图中的要求

How to validate required in nested map

我正在使用 Elixir。

我收到了一些属性,我正在使用它们创建一个 location。属性类似于:

attrs = %{latitude: 123.2, longitude: 123.4, metadata: %{timestamp: "2015-05-05T01:31:54", accuracy: 1}}

创建我使用:

location
|> cast(attrs, [:latitude, :longitude, :metadata])
|> validate_required([:latitude, :longitude])

有什么方法可以验证 metadata.timestamp 的要求吗? 谢谢!

您可以为您的元数据创建另一个架构,然后嵌入一个 Metadata。这将使您能够投射和验证元数据中的字段。代码如下所示:

defmodule Location do
  use Ecto.Schema

  schema "location" do
    field :latitude, :float
    field :longitude, :float
    embeds_one :metadata, Metadata
  end

  def changeset(location, attrs) do
     location
     |> cast(attrs, [:latitude, :longitude, :metadata])
     |> validate_required([:latitude, :longitude])
     |> cast_embed(:metadata)
  end
end

和您的元数据:

defmodule Metadata do
  use Ecto.Schema

  embedded_schema do
    field :timestamp, :utc_datetime
    field :accuracy, :integer
  end

  def changeset(metadata, attrs) do
    location
    |> cast(attrs, [:timestamp, :accuracy])
    |> validate_required([:timestamp])
  end
end

这将是使用 Ecto Schemas 进行结构验证嵌套映射的方法,但是 ofc。您可以编写自己的验证函数,here 是一个关于如何做到这一点的示例。

使用 Harun 回答的部分内容和来自不同论坛的另一个回答,我解决了这个问题:

defp validate_metadata_contains_timestamp(changeset, field) do
  validate_change(changeset, field, fn (current_field, value) ->
    case Map.fetch(value, "timestamp") do
      {:ok, _} -> []
      :error -> [{current_field, "The field metadata must have a timestamp"}]
    end
  end)
end