将某些变更集字段转换为 ecto :map 字段

Cast certain changeset fields into an ecto :map field

我有一个如下所示的变更集:

%{
  creator_id: "4",
  name: "a test with GraphQL",
  place_id: "13",
  entree_id: "8",
  base: "wheat",
  type: "food"
}

我的ecto schema如下:

schema "items" do
  field :type, :string
  field :name, :string
  field :data, :map

  belongs_to :creator, Name.SubName.Creators
  belongs_to :place,   Name.SubName.Places
  belongs_to :entree,  Name.SubName.Entrees

  timestamps()
end

如您所见,base 不是 ecto 模式中的字段,我想将 base 转换为 data 字段,以便它是 map类型,即:{"base":"wheat"}。我在这里使用某种形式的单一 table 继承。

我正在尝试向我的 items table 添加一条记录。现在,当我从 table 读取时,我将 data 字段转换为包含我的 base 字段的嵌入式架构(取决于 type)。我挣扎的地方是将这个字段放回数据库中。

我尝试使用 Ecto.Changeset.cast(params[:base], Map.keys(%{data: :map})) 之类的东西,但显然它只是得到了显然不是有效地图的值。此外,为与代表每个 type 的其他嵌入式模式关联的所有唯一字段指定将很痛苦。

embeds_oneembeds_many 不适用于这种情况,因为 data ecto 字段表示不同的嵌入式模式类型。所以在这种情况下,我的问题不是关于嵌入式模式的使用,而是更多关于在 changeset 中挑选特定字段并将它们变成 map。我的一半只是认为我应该为每个 type 制作一个不同的 table 然后我就不必担心这个了。

您可以使用Map.split/2:

@required_fields [:name, :type, :creator_id, :place_id, :entree_id]
@all_fields [:data | @required_fields]

def changeset(struct, params) do
  {allowed, others} = Map.split(params, @required_fields)
  params = Map.put(allowed, :data, others)

  struct
  |> cast(params, @all_fields)
  |> # ...
end

这里要注意的重要一点是,此示例仅适用于具有原子键的映射,您必须对其进行一些修改才能同时使用字符串键和原子键。您还可以考虑将空映射指定为 :data.

的默认值