【问题标题】:How to preserve Id's of associated models with nested forms for has_many Ecto associations?如何使用 has_many Ecto 关联的嵌套形式保留关联模型的 ID?
【发布时间】:2017-10-21 05:28:18
【问题描述】:

我找不到关于使用带有动态添加的关联模型字段的嵌套表单更新具有 has_many 关联的模型的信息,我只能找到关于插入新模型的信息。

但是当我们更新父模型时,我们有时需要注意保留关联子模型的 ID。

鉴于我们有两个模型,具有这样的 has_many 关系:

父.ex

defmodule MyApp.Parent do
  use MyApp.Web :model

  schema "parents" do
    field :name, :string
    has_many :children, MyApp.Child
    timestamps
  end

  def changeset(parent, params \\ %{}) do
    parent
    |> cast(params, [:name])
    |> validate_required([:name])
    |> cast_assoc(:children)    
  end
end

child.ex

defmodule MyApp.Child do
  use MyApp.Web :model

  schema "children" do
    field :name, :string
    belongs_to :parent, MyApp.Parent
    timestamps
  end

  def changeset(child, params \\ %{}) do
    child
    |> cast(params, [:name])
    |> validate_required([:name])    
  end
end

Parent 的嵌套表单与 inputs_for 的子级如下:

form.html.eex

  <%= form_for @changeset, @action, fn f -> %>
    <%= if @changeset.action do %>
      <div class="alert alert-danger">
        <p>Oops, something went wrong! Please check the errors below.</p>
      </div>
    <% end %>
  <div class="form-group">
    <%= label f, :name, class: "control-label" %>
    <%= text_input f, :name, class: "form-control" %>
    <%= error_tag f.source, :name %>
  </div>
  <%= inputs_for f, :children, [append: [MyApp.Child.changeset(%Child{})]], fn fc -> %>
    <div class="form-group">
      <%= label fc, :name, class: "control-label" %>
      <%= text_input fc, :name, class: "form-control" %>
      <%= error_tag fc.source, :name %>
    </div>
    <div class="form-group">
      <%= checkbox fc, :delete, class: "delete-checkbox" %>
    </div>
  <% end %> <!-- end the nested children -->
  <%= submit "Submit" %>
<% end %>

在一些 javascript 的帮助下,它还可以添加更多的子表单。

问题:

如果我想在父级的 update 操作中保留子级 ID,我是否需要将隐藏的 Id 表单字段添加到所有现有子级,并将它们添加到允许的字段以在 MyApp.Child 中进行函数调用。变更集?或者是否有其他方法可以强制 Ecto 更新旧子代,而不是移除旧子代并使用新 ID 创建新子代?

【问题讨论】:

  • 在隐藏字段中传递 id 对您有用吗?根据cast_assoc 的文档,如果id 存在且有效(存在且属于父级),则记录将被更新,否则将插入新记录。见hexdocs.pm/ecto/Ecto.Changeset.html#cast_assoc/3
  • 我仍在思考这个问题,困扰我的是我从未见过使用隐藏字段方法的示例,并且我已经查看了其中的许多。不过,我已经通过您的链接查看了文档,似乎 cast_assoc 负责防止意外更新其他模型的孩子,这很好。
  • @Dogbert:看来至少在我的安装中(Phoenix 1.3.0-rc.2,Ecto 3.2.3)隐藏的Id字段神奇地出现在了post编辑表单中,所以没有必要要手动将这些字段添加到表单模板,它们已经存在。是的,cmets 的 ID 在更新后仍然存在。我试图弄清楚是谁为我生成了这些字段,但到目前为止还没有找到。

标签: phoenix-framework nested-forms has-many insert-update ecto


【解决方案1】:

是的,您确实需要为 ID 添加隐藏字段,否则将被视为插入操作。如果您发送 ID,这将是一个更新。

您不需要将 :id 字段添加到子变更集中的演员表中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    相关资源
    最近更新 更多