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