如何使用Phoenix框架处理可选的嵌套输入?

时间:2016-06-26 20:30:06

标签: phoenix-framework

Phoenix通过可选的“inputs_for”嵌套表单输入导致控制器中的映射未通过验证。例如,帖子有评论。如果我想在创建帖子时为帖子添加注释,嵌套表单将如下所示:

<%= form_for @changeset, @action, fn p -> %>
  <%= text_input p, :body %>
  <%= inputs_for p, :comments, fn c -> %>
    <%= text_input c, :body %>
  <% end %>
<% end %>

我填写帖子正文,但这次没有为评论添加任何内容。这将为我们提供

控制器中的params [“post”]地图
%{
  "body" => "My post",
  %{"comments" => %{"0" => %{"body" => ""}}
}

但是,评论是“可选的”。因此,为注释完成的验证将失败,因为有一个正文但它是空的。

接下来的问题是,如果注释为空,我们如何删除/清除注释,但如果它有某些值,请保留它?擦除params“post”似乎没有成功。

2 个答案:

答案 0 :(得分:1)

我想您必须编写自己的scrub_comments function plug,这将从评论地图中删除空评论,并最终删除评论为空。

答案 1 :(得分:0)

这是克里斯提到的那种方法。以下内容是从我的工作版本修改而来的,可以处理帖子和评论,并且未经测试,但至少应显示该方法。

帮助程序模块:

defmodule MyappWeb.Helpers do
  alias MyappWeb.Post

  def filter_post_params(%Plug.Conn{:params => %{"post" => %{"comments" => _}}} = conn, _opts) do
    filtered_params =
      conn.params
      |> get_in(["post"])
      |> Enum.reject(fn({_, x}) -> match?(%{"comments" => nil}, x) end)
      |> Enum.into(%{})
    new_params = put_in(conn.params, ["post"], filtered_params)

    %Plug.Conn{conn | params: new_params}
  end
  def filter_post_params(%Plug.Conn{} = conn, _opts), do: conn
end

控制器,使用Phoenix的scrub_params插头和我们的filter_post_params插头,从上方:

defmodule MyappWeb.PostController do
  use MyappWeb, :controller

  alias Myapp.Post

  plug :scrub_params, "post" when action in [:create, :update]
  plug :filter_post_params when action in [:create, :update]

  # ...
end