处理Phoenix中许多表单的变更集

时间:2017-07-07 19:18:03

标签: forms elixir phoenix-framework ecto

我想写一个论坛网站。在特定主题的页面上,用户可以添加新帖子并评论以前的帖子(他们无法评论评论)。我的第一个想法是为新帖子和每个评论创建单独的表单,我为所有这些表单创建了单独的更改集。但是在使用这种方法添加新帖子/评论失败时,我必须再次创建所有新的变更集,并且还要找到真正使用的变更集,并将其替换为我认为有点难看的错误消息。在凤凰城有更好的方法吗?

def index(conn, %{"topic_id" => topic_id}, _current_user) do
  topic = Forum.get_topic!(topic_id)
  render(
    conn,
    "index.html",
    topic: topic,
    changesets: create_changesets(topic.posts))
end

def add_post(conn, %{"topic_id" => topic_id, "post" => post_params}, current_user) do
  case Forum.create_post(current_user, topic, post_params) do
    {:ok, _post} ->
      redirect(conn, to: topic_path(conn, :index, topic_id))
    {:error, changeset} ->
      topic = Forum.get_topic!(topic_id)
      render(
        conn,
        "index.html",
        topic: topic,
        changesets: create_changesets(topic.posts, changeset))
  end
end

def add_comment(conn, %{"topic_id" => topic_id, "post_id" => post_id, "comment" => comment_params}, current_user) do
  post = Forum.get_post!(post_id)
  case Forum.create_comment(current_user, post, comment_params) do
    {:ok, _comment} ->
      redirect(conn, to: topic_path(conn, :index, topic_id))
    {:error, changeset} ->
      topic = Forum.get_topic!(topic_id)
      render(
        conn,
        "index.html",
        topic: topic,
        changesets: create_changesets(topic.posts, changeset))
  end
end

# ugly part
defp create_changesets(posts) do
  create_changesets(posts, Forum.change_post(%Forum.Post{}))
end
defp create_changesets(posts, %Ecto.Changeset{data: %Forum.Post{}} = changeset) do
  comments_changesets = for _ <- posts do
    Forum.change_comment(%Forum.Comment{})
  end
  %{posts: changeset, comments: comments_changesets}
end
defp create_changesets(posts, %Ecto.Changeset{data: %Forum.Comment{}} = changeset) do
  comments_changesets = for post <- posts do
    if post.id == changeset.data.forum_post_id do
      changeset
    else
      Forum.change_comment(%Forum.Comment{})
    end
  end
  %{posts: Forum.change_post(%Forum.Post{}), comments: comments_changesets}
end

模板:

<%= @topic.title %>
<ul>
  <%= render "post_form.html", changeset: @changesets.posts,
    action: topic_path(@conn, :add_post, @topic.id) %>
  <%= for {post, comment_changeset} <- Enum.zip(@topic.posts, @changesets.comments) do %>
    <li>
      <%= post.inserted_at %>
      <%= post.text %>
    </li>
    <ul>
      <%= for comment <- post.comments do %>
        <li><%= comment.text %> - <%= comment.inserted_at %></li>
      <% end %>
      <%= render "comment_form.html", changeset: comment_changeset,
        action: topic_path(@conn, :add_comment, @topic.id, post.id) %>
    </ul>
  <% end %>
</ul>

0 个答案:

没有答案