PhoenixとElixirを使用してブログエンジンを作成する/パート7。コメントを追加する/新年の発表を締めくくる





翻訳者から:「 エリクサーとフェニックスは、最新のウェブ開発がどこに進んでいるかの良い例です。 すでにこれらのツールは、Webアプリケーションのリアルタイムテクノロジーへの質の高いアクセスを提供します。 対話性が向上したサイト、マルチユーザーブラウザーゲーム、マイクロサービスは、これらの技術がうまく機能する分野です。 以下は、Phoenixフレームワークでの開発の詳細な側面を説明する一連の11の記事の翻訳です。ブログエンジンのような些細なことのように思えます。 しかし、急いでつまずかないでください。特に記事がエリクサーに注意を払うか、彼のフォロワーになるように促す場合、それは本当に面白いでしょう。



このパートでは、Phoenixチャンネルを使用してアニメーション化できるように、コメントの基盤を準備します。



現時点では、アプリケーションは以下に基づいています。





どこで止めたの



エンジンは小さなMarkdownエディターを使用して投稿を装飾できるようになったため、私たちのクラフトは本格的なプロジェクトのようになりました! ただし、作成した投稿に関するフィードバックを受け取る方法はまだありません。 幸いなことに、この機能の追加は非常に簡単です。 すべての作業は、すでに行ったことに基づいて行われます。



簡単なものから始めましょう。 登録の要件の代わりに、承認待ちの状態で新しいコメントを作成します。 コメントは、確認後すぐに投稿ページに表示されるか、「未確認を表示」をクリックして表示されます。



コメントモデルを追加



コメント用のモデルを追加することから始めましょう。 コメントは次のとおりです。





テンプレートやその他のアメニティの完全なセットは必要ないため、 mix phoenix.gen.model



を使用します。



 mix phoenix.gen.model Comment comments author:string body:text approved:boolean post_id:references:posts
      
      





次に、移行します。



 mix ecto.migrate
      
      





コメントを投稿にリンクする



web/models/comment.ex



は、コメントがすでに投稿に関連付けられていることがわかりますが、反対方向のコミュニケーションは十分ではありません。



したがって、 web/models/post.ex



ファイルの「posts」スキーマの定義に次のコードを追加します。



 has_many :comments, Pxblog.Comment
      
      





mix test



コマンドを実行した後、すべてが緑色になっているはずです! では、投稿とコメントの関係を確認しましょう。



これを行うには、ファイルtest/support/factory.ex



を開き、コメントファクトリを追加します。 ファイルの先頭に次の行を書き、その後に他のエイリアスを続けます。



 alias Pxblog.Comment
      
      





そして、このコードを一番下に:



 def comment_factory do %Comment{ author: "Test User", body: "This is a sample comment", approved: false, post: build(:post) } end
      
      





したがって、ファクトリが有用になるように、いくつかのテストを作成する必要があります。 ファイルtest/models/comment_test.exs



を開き、次のコードを追加します。



 import Pxblog.Factory # ... test "creates a comment associated with a post" do comment = insert(:comment) assert comment.post_id end
      
      





テストを再度実行します。 彼らは緑のままでなければなりません!



コメントのルートを追加する



基本的なコメントルートを作成することから始めましょう。 web/router.ex







 resources "/posts", PostController, only: [] do resources "/comments", CommentController, only: [:create, :delete, :update] end
      
      





コメントは投稿のコンテキストでのみ意味があるため、コメントを内部に配置します。 同時に、すでに特定した他のルートでは、投稿はユーザーに投資されます! 投稿に不要なルートを作成したくないので、 only: []



パラメーターonly: []



使用します。 次に、コメント用のリソースを追加して、コメントを作成、削除、更新できるようにします。 :create



承認されていないユーザーによるコメントを追加します(未確認によって作成されます)。 :delete



-投稿の作成者および管理者がコメントを削除できるようにします。 :update



-公開表示のためにコメントを承認します。



コントローラーとビューを追加する



モデルが構成されたので、いくつかの方法でコントローラーを作成する必要があります。 コメントの表示はポストコントローラーを介して実装されますが、作成/更新/削除は独自のコントローラーで実装する必要があります。 web/controllers/comment_controller.ex



ファイルを作成することから始めましょう:



 defmodule Pxblog.CommentController do use Pxblog.Web, :controller end
      
      





また、web / views / comment_view.exファイルに、Phoenixが望むようにビューを作成します。



 defmodule Pxblog.CommentView do use Pxblog.Web, :view end
      
      





それでは、コントローラーに戻って、 create



update



およびdelete



の3つのアクションの基本構造を追加しましょう。



 def create(conn, _), do: conn def update(conn, _), do: conn def delete(conn, _), do: conn
      
      





次に、新しいディレクトリにコメントを追加するためのテンプレートを作成する必要があります。これは、投稿を表示するページに配置します。



 $ mkdir web/templates/comment
      
      





ユーザーがコメントを残すことを許可します。



web/templates/comment/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, :author, class: "control-label" %> <%= text_input f, :author, class: "form-control" %> <%= error_tag f, :author %> </div> <div class="form-group"> <%= label f, :body, class: "control-label" %> <%= textarea f, :body, class: "form-control", id: "body-editor" %> <%= error_tag f, :body %> </div> <div class="form-group"> <%= submit "Submit", class: "btn btn-primary" %> </div> <% end %>
      
      





通常の形式、議論することは何もありません。



次に、 web/templates/post/show.html.eex



ファイルに移動して、このフォームへのリンクを追加します。 このテンプレートでは、2つの変数@changeset



@action



を使用していることに注意してください。 これについては、 web/controllers/post_controller.ex



。 そして今、私たちはテンプレートを使い続けています。 投稿属性のリストの後に、次の行を追加します。



 <%= render Pxblog.CommentView, "form.html", changeset: @comment_changeset, action: post_comment_path(@conn, :create, @post) %>
      
      





CommentView内の "form.html"を参照する必要があるため、 render



呼び出しの最初の引数として名前を渡します。 @comment_changeset



を渡す必要があり@comment_changeset



(まだ決定していませんが、すぐに行います)。 @action



はコメントを送信する方法です。



これで、 web/controllers/post_controller.ex



に移動して機能させることがweb/controllers/post_controller.ex



。 コードに一致するようにshow関数を変更します。



 def show(conn, %{"id" => id}) do post = Repo.get!(assoc(conn.assigns[:user], :posts), id) comment_changeset = post |> build_assoc(:comments) |> Pxblog.Comment.changeset() render(conn, "show.html", post: post, comment_changeset: comment_changeset) end
      
      





次に、CommentController(ファイルweb/controllers/comment_controller.ex



)に戻り、作成関数に内容を入力します。 関数の直前に、次のコードを追加します。



 alias Pxblog.Comment alias Pxblog.Post plug :scrub_params, "comment" when action in [:create, :update]
      
      





scrub_params呼び出しに更新を含めることは、後で役立ちます。 create関数にジャンプして、次のコードをその中に配置します。



 def create(conn, %{"comment" => comment_params, "post_id" => post_id}) do post = Repo.get!(Post, post_id) |> Repo.preload([:user, :comments]) changeset = post |> build_assoc(:comments) |> Comment.changeset(comment_params) case Repo.insert(changeset) do {:ok, _comment} -> conn |> put_flash(:info, "Comment created successfully!") |> redirect(to: user_post_path(conn, :show, post.user, post)) {:error, changeset} -> render(conn, Pxblog.PostView, "show.html", post: post, user: post.user, comment_changeset: changeset) end end
      
      





ここで、comment_paramsおよびpost_id投稿識別子を受け取るときに、必要に応じてコメントを作成します。 まず、リンクされた投稿をピックアップします(テンプレートが間もなくリンクを開始するため、ユーザーとコメントをプリロードすることを忘れないでください)。これに基づいて、新しいチェンジセットを作成します。 これを行うには、ポストから始めて、チェーンに沿ってbuild_assoc



関数にbuild_assoc



、接続された回路を作成します。これはアトムを通じて定義します。 この場合、リンクされたcomment



が作成されます。 結果は、comment_paramsとともに、Comment.changeset関数に渡されます。 残りは1つの例外を除いて標準として機能します。



別のビューのレンダリングを使用しているため、エラー条件はもう少し複雑です。 まず、接続接続を渡し、次に関連するビュー(この場合はPxblog.PostView



)、レンダリング用のテンプレート、およびテンプレートで使用されるすべての変数@post



@user



@post



@user



@comment_changeset



ます。 これでテストできます。エラーのあるコメントを送信すると、ページにそれらのリストが表示されます。 コメントの送信時にエラーがない場合は、ページの上部に青いフラッシュメッセージが表示されます。



コメント出力



次に、投稿ページにコメントを表示する必要があります。 これを行うには、さまざまな目的で任意の場所で使用できる一般的なコメントテンプレートを作成します。 web/templates/comment/comment.html.eex



を作成し、以下を入力します:



 <div class="comment"> <div class="row"> <div class="col-xs-4"> <strong><%= @comment.author %></strong> </div> <div class="col-xs-4"> <em><%= @comment.inserted_at %></em> </div> <div class="col-xs-4 text-right"> <%= unless @comment.approved do %> <button class="btn btn-xs btn-primary approve">Approve</button> <% end %> <button class="btn btn-xs btn-danger delete">Delete</button> </div> </div> <div class="row"> <div class="col-xs-12"> <%= @comment.body %> </div> </div> </div>
      
      





ここでは説明なしですべてが明確です。 承認/削除ボタンはまだ接続されていません。 この問題は次の部分で解決します。 また、コメントをプリロードするようにコントローラーを変更し、ショー投稿テンプレートにコメントのリストを含める必要があります。 コントローラーを更新することから始めましょう。 投稿を受信する行の直後に、 web/controllers/post_controller.ex



からshow



関数に行を追加しweb/controllers/post_controller.ex







 post = Repo.get!(assoc(conn.assigns[:user], :posts), id) |> Repo.preload(:comments)
      
      





このようにして、コメントが投稿の一部としてロードされるようにします。 最後に、 web/templates/post/show.html.eex



ファイルを開き、コメントを表示するテンプレートセクションを追加します。



 <div class="comments"> <h2>Comments</h2> <%= for comment <- @post.comments do %> <%= render Pxblog.CommentView, "comment.html", comment: comment %> <% end %> </div>
      
      





コントローラーテストを追加する



いくつかの条件がテストでカバーされるまで停止できません。 コードはこれらのパスのいずれかを通過できるため、成功と失敗の場合にcreate関数をチェックする必要があります。



ファイルtest/controllers/comment_controller_test.exs



を作成して続行します。



 defmodule Pxblog.CommentControllerTest do use Pxblog.ConnCase import Pxblog.Factory @valid_attrs %{author: "Some Person", body: "This is a sample comment"} @invalid_attrs %{} setup do user = insert(:user) post = insert(:post, user: user) {:ok, conn: build_conn(), user: user, post: post} end test "creates resource and redirects when data is valid", %{conn: conn, post: post} do conn = post conn, post_comment_path(conn, :create, post), comment: @valid_attrs assert redirected_to(conn) == user_post_path(conn, :show, post.user, post) assert Repo.get_by(assoc(post, :comments), @valid_attrs) end test "does not create resource and renders errors when data is invalid", %{conn: conn, post: post} do conn = post conn, post_comment_path(conn, :create, post), comment: @invalid_attrs assert html_response(conn, 200) =~ "Oops, something went wrong" end end
      
      





再びPxblog.Factoryファクトリを使用しましょう。 また、2つのモジュール変数@valid_attrs



および@invalid_attrs



を以前と同じ方法で設定します。 セットアップブロックを追加します。セットアップブロック内で、既定のユーザーと作業する投稿を構成します。



コメントを正常に追加するためのテストから始めましょう。 有効な属性を持つネストされたパスにPOSTリクエストを送信し、期待どおりにリダイレクトが機能し、コメントが投稿に追加されたことを確認します。



次に、同じことを行いますが、無効なデータを使用して、HTMLの形式で「エラーが発生しました」というメッセージを受け取ったことを確認します。 できた!







さらなるステップ



コメントのための素晴らしい基盤を用意しました。これは間違いなく開発を続けることができます。 たとえば、コメントを承認または削除することはできません。 次のいくつかのパートでは、Phoenixベースのライブコメントシステムに移行する前に、コメントの改善にもう少し取り組んでいきます。



シリーズの他の記事



  1. エントリー
  2. ログイン
  3. 役割を追加
  4. コントローラーで役割を処理します
  5. ExMachinaを接続します
  6. マークダウンのサポート
  7. コメントを追加
  8. コメントで終了
  9. チャンネル
  10. チャネルテスト
  11. おわりに




Wunschからの結論



今年の2か月で、エリクサーのプロモーションの第一歩を踏み出すことができました。 まず、ロシア語コミュニティのWunsh.ruを設立しました。このコミュニティのために 、Elixirと関数型プログラミングに関する最も興味深い記事の1つ半をロシア語に翻訳しました。



週の初めに、サイトを更新し、5つの記事を共有しました。 彼らがあなたをいらいらさせ、あなたにその言語を試すよう説得してくれることを願っています。 たとえば、シンプルな冬休みアプリを作成します。 明日は、購読者に公開された記事の完全なセットを送信します。 だから今日サインアップして友達を招待してください 。 このような贈り物を楽しみにしています!



プロジェクトの次のステップは、初心者向けの本格的な紹介を書き、公式ドキュメントを翻訳し、一般的な質問に詳細に答えることです。





その他



来年は、言語自体の急速な動きでいっぱいになります。 ロシア企業への導入。 彼らは言語について知るだけでなく、(可能な限り)それを大規模に使い始めるでしょう。



資料をご覧いただきありがとうございます。 あなたが加入者である場合、あなたの友人を招待してください。



来てすべて!



All Articles