【问题标题】:Cast certain changeset fields into an ecto :map field将某些变更集字段转换为 ecto :map 字段
【发布时间】:2018-11-03 00:11:20
【问题描述】:

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

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

我的ecto架构如下:

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"} .我在这里使用某种形式的单表继承。

我正在尝试向我的items 表中添加一条记录。现在,当我从表中读取数据时,我将data 字段转换为包含我的base 字段的嵌入式模式(取决于type)。我努力的地方是将这个字段重新输入数据库。

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

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

【问题讨论】:

    标签: elixir ecto single-table-inheritance


    【解决方案1】:

    你可以使用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 的默认值。

    【讨论】:

    • 谢谢!这就是诀窍......现在我必须决定这是否真的是我想做的事情。看起来有点脆弱,但现在可以了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    相关资源
    最近更新 更多