我看到你正在使用put_embed
,但我不认为从产品架构。我不知道这是否是真正的问题。但我尝试了一些可行的代码。
我使用Blog和Post模型创建了一个新应用程序。我使用生成模型:
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
我手动创建一个职位has_many
协会(它没有与我产生模型创建)。现在,我们有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
)玩:
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
我抑制一些输出集中的错误。 Changeset
就像一棵树。所以,你可以拥有父变更集和孩子。与你的代码不同的是,我使用的是put_assoc
(https://hexdocs.pm/ecto/Ecto.Changeset.html#put_assoc/4)(也许是关系,但我没有看到你的模式)。
行为从put_assoc
预期:
如果联想没有任何变化,它会被跳过。如果关联无效,则更改集将被标记为无效。如果给定的价值不是一个关联,它就会增加。
我希望这可以帮助你。
这是一个了不起的答案埃里克,感谢你写了。我最终在自己的表中实现了一些东西,所以我无法测试你的答案,但是要感谢它被打出来喜欢这个。 – Samuel