Elixir Phoenix框架和验证嵌入

Elixir Phoenix框架和验证嵌入,elixir,phoenix-framework,Elixir,Phoenix Framework,鉴于以下代码工作正常: image_1 = %Image{naturalHeight: "100", naturalWidth: 100} diffbot_objects = [ %DiffbotObject{ availability: true, images: [ image_1 ] } ] changeset = Ecto.Changeset.change(product) changeset = Ecto.Changeset.put_em

鉴于以下代码工作正常:

image_1 = %Image{naturalHeight: "100", naturalWidth: 100}

diffbot_objects = [
  %DiffbotObject{
    availability: true,
    images: [
      image_1
    ]
  }
]

changeset = Ecto.Changeset.change(product)
changeset = Ecto.Changeset.put_embed(changeset, :diffbot_objects, diffbot_objects)
如何确保在图像模型上验证字段?我可以使用图像模型上的changeset方法生成一个变更集(见下文),但我无法使用嵌套的变更集插入数据,它必须是e struct

我的图像模型:

defmodule Shopshare.Product.DiffbotObject.Image do
  use Shopshare.Web, :model

  embedded_schema do
    field :naturalHeight, :integer
    field :naturalWidth, :integer
  end

  @required_fields ~w(naturalHeight, naturalWidth)
  @optional_fields ~w()

  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
  end
end

我看到您正在使用
put\u embed
,但我没有看到产品中的模式。我不知道这是否是真正的问题。但我尝试了一些有效的代码

我用博客和帖子模式创建了一个新应用程序。我使用了生成模型:

mix phoenix.gen.model Blog blogs name:string
mix phoenix.gen.model Post posts title:string body:text blog_id:references:blogs
我对必填字段使用一个简单的验证。让我们深入研究博客模式:

    defmodule MyApp.Blog do
      use MyApp.Web, :model

      schema "blogs" do
        field :name, :string
        has_many :posts, MyApp.Post

        timestamps
      end

      @required_fields ~w(name)
      @optional_fields ~w()

      def changeset(model, params \\ :empty) do
        model
        |> cast(params, @required_fields, @optional_fields)
      end
    end
我手动创建的
与帖子有很多关联(它不是用我的生成模型创建的)。现在,我们有了Post模型:

    defmodule MyApp.Post do
      use MyApp.Web, :model

      schema "posts" do
        field :title, :string
        field :body, :string
        belongs_to :blog, MyApp.Blog

        timestamps
      end

      @required_fields ~w(title body)
      @optional_fields ~w()

      def changeset(model, params \\ :empty) do
        model
        |> cast(params, @required_fields, @optional_fields)
      end
    end
现在,我们可以在IEx中玩(
IEx-S mix
):

我抑制了一些输出以在错误中聚焦<代码>变更集
像树一样工作。因此,您可以拥有父变更集和子变更集。与您的代码不同的是,我使用的是
put_assoc
()(也可能是关系,但我没有看到您的模式)

put\u assoc
预期的行为:

如果关联没有更改,将跳过它。如果关联无效,变更集将被标记为无效。如果给定的值不是关联,它将升高


我希望这能对你有所帮助。

这是一个非常好的答案,埃里克,谢谢你写下来。最后我在他们自己的表中实现了一些东西,所以我不能测试你的答案,但是很感谢你像这样输入答案。
    iex(1)> blog_changeset = MyApp.Blog.changeset(%MyApp.Blog{}, %{name: "blog name"})
    %Ecto.Changeset{...}

    iex(2)> blog_changeset.valid?
    true

    iex(3)> invalid_post_changeset = MyApp.Post.changeset(%MyApp.Post{}, %{})
    %Ecto.Changeset{...}

    iex(4)> blog_changeset = Ecto.Changeset.put_assoc(blog_changeset, :posts, [invalid_post_changeset])
    %Ecto.Changeset{action: nil,
    changes: %{name: "blog name",
      posts: [%Ecto.Changeset{action: :insert,
        changes: ..., constraints: [],
        errors: [title: "can't be blank", body: "can't be blank"], filters: %{},
        ...]}, ...,
    model: %MyApp.Blog{...}, optional: [], opts: [], params: %{"name" => "blog name"},
    prepare: [], repo: nil, required: [:name],
    types: %{...},
    valid?: false, validations: []}

    iex(5)> blog_changeset.valid?
    false