我看到你正在使用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