【Phoenix1.4】（後編）パスワード認証＆リレーションあり「ブログチュートリアル」

# |> いいよね！Elixir！
（この記事は **[Elixir Advent Calendar 2018](https://qiita.com/advent-calendar/2018/elixir)** 6日目です。前回は[kikuyuta](https://qiita.com/kikuyuta)さんの[Elixir を使うようになった経緯 〜電力システム制御の現場から〜](https://qiita.com/kikuyuta/items/96c3f91a850e9274b0e9)です！）

前編は「[fukuoka.ex Elixir／Phoenix Advent Calendar 2018](https://qiita.com/advent-calendar/2018/fukuokaex)」の2日目に掲載しています
 **|> [【Phoenix1.4】（前編）パスワード認証＆リレーションあり「ブログチュートリアル」](https://qiita.com/koyo-miyamura/items/82f6735a911339bc6607)**

それでは後半をお楽しみ下さい！

## |> 自分自身のuserリソースのみ変更できるように修正
### |> userリソース
さて前編までで、基本的なログイン機能はできたのですが、今のままだと他の人のユーザアカウントをeditしたりdeleteすることができてしまいます
userコントローラのshowやindexメソッドは許可してedit, update, deleteメソッドを許可しないような実装にしてみましょう

現状こうなっていますが

```elixir:lib/ex_blog_web/controllers/user_controller.ex
defmodule ExBlogWeb.UserController do
  use ExBlogWeb, :controller

  alias ExBlog.Accounts
  alias ExBlog.Accounts.User

  def index(conn, _params) do
    users = Accounts.list_users()
    render(conn, "index.html", users: users)
  end

  def new(conn, _params) do
    changeset = Accounts.change_user(%User{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    case Accounts.create_user(user_params) do
      {:ok, _user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: Routes.page_path(conn, :index))

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    render(conn, "show.html", user: user)
  end

  def edit(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    changeset = Accounts.change_user(user)
    render(conn, "edit.html", user: user, changeset: changeset)
  end

  def update(conn, %{"id" => id, "user" => user_params}) do
    user = Accounts.get_user!(id)

    case Accounts.update_user(user, user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User updated successfully.")
        |> redirect(to: Routes.user_path(conn, :show, user))

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "edit.html", user: user, changeset: changeset)
    end
  end

  def delete(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    {:ok, _user} = Accounts.delete_user(user)

    conn
    |> put_flash(:info, "User deleted successfully.")
    |> redirect(to: Routes.user_path(conn, :index))
  end
end
```

以下のように変更します
プライベートメソッドである`is_authorized`を定義して、アクセスしたuserリソースのidとログイン中のuserのidが一致するかを確かめます
edit, update, deleteメソッドの実行前に`is_authorized`を実行するPlugを定義します（Railsでいうとbefore_actionみたいなの）
各edit, update, deleteの実行はis_authrizedの後、つまりcurrent_userに対する操作だけすればいいのでリクエストのidは気にしなくてよくなります
あと、ついでにuser登録後についでにログインするようにしておきます

```diff:lib/ex_blog_web/controllers/user_controller.ex
defmodule ExBlogWeb.UserController do
  use ExBlogWeb, :controller

  alias ExBlog.Accounts
  alias ExBlog.Accounts.User
+  alias ExBlog.Accounts.Guardian
+
+  plug :is_authorized when action in [:edit, :update, :delete]

  def index(conn, _params) do
    users = Accounts.list_users()
    render(conn, "index.html", users: users)
  end

  def new(conn, _params) do
    changeset = Accounts.change_user(%User{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    case Accounts.create_user(user_params) do
-      {:ok, _user} ->
+      {:ok, user} ->
        conn
        |> put_flash(:info, "User created successfully.")
-        |> redirect(to: Routes.page_path(conn, :index))
+        |> Guardian.Plug.sign_in(user)
+        |> redirect(to: Routes.user_path(conn, :show, user))

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    render(conn, "show.html", user: user)
  end

-  def edit(conn, %{"id" => id}) do
-    user = Accounts.get_user!(id)
-    changeset = Accounts.change_user(user)
-    render(conn, "edit.html", user: user, changeset: changeset)
+  def edit(conn, _) do
+    changeset = Accounts.change_user(conn.assigns.current_user)
+    render(conn, "edit.html", user: conn.assigns.current_user, changeset: changeset)
  end

-  def update(conn, %{"id" => id, "user" => user_params}) do
-    user = Accounts.get_user!(id)
+  def update(conn, %{"user" => user_params}) do
+    user = conn.assigns.current_user

    case Accounts.update_user(user, user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User updated successfully.")
        |> redirect(to: Routes.user_path(conn, :show, user))

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "edit.html", user: user, changeset: changeset)
    end
  end

-  def delete(conn, %{"id" => id}) do
-    user = Accounts.get_user!(id)
-    {:ok, _user} = Accounts.delete_user(user)
+  def delete(conn, _) do
+    {:ok, _user} = Accounts.delete_user(conn.assigns.current_user)

    conn
+    |> Guardian.Plug.sign_out()
    |> put_flash(:info, "User deleted successfully.")
-    |> redirect(to: Routes.user_path(conn, :index))
+    |> redirect(to: Routes.page_path(conn, :index))
  end

+  defp is_authorized(conn, _) do
+    current_user = Accounts.current_user(conn)
+     if current_user.id == String.to_integer(conn.params["id"]) do
+      assign(conn, :current_user, current_user)
+    else
+      conn
+      |> put_flash(:error, "You can't modify that page")
+      |> redirect(to: Routes.page_path(conn, :index))
+      |> halt()
+    end
+  end
end
```

accountsに現在のユーザを返すメソッドを追加します

```diff:lib/ex_blog/accounts/accounts.ex
+  def current_user(conn) do
+    Guardian.Plug.current_resource(conn)
+  end
```

これで自分以外のuserリソースをeditやupdateやdeleteしようとすると以下のようにフラッシュが出ます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/08fc7836-fa69-1231-4f12-524a53bd8f68.png)


articleリソースも同様に権限管理できますが、ログインを実装しarticleのcreateにuserリソースを関連付けることができるようになったので、まずはリレーションから進めていきたいと思います

## |> リレーションを使って特定のuserが持つarticleの一覧を表示させる
さて、まずはuserが属するAccountsコンテキストとarticleが属するBlogコンテキストを変更します
articleやuserを取得するときに`Repo.preload()`をパイプさせることで、リレーション先のテーブルを取得できます
また、create_articleメソッドではuserを引数に取り、そのidをuser_idカラムに追加する処理を追加します

```diff:lib/ex_blog/accounts/accounts.ex
defmodule ExBlog.Accounts do
  @moduledoc """
  The Accounts context.
  """

  import Ecto.Query, warn: false
  alias ExBlog.Repo

  alias ExBlog.Accounts.User
  alias Comeonin.Bcrypt
+  alias ExBlog.Accounts.Guardian

  @doc """
  Returns the list of users.

  ## Examples

      iex> list_users()
      [%User{}, ...]

  """
  def list_users do
-    Repo.all(User)
+    User
+    |> Repo.all()
+    |> Repo.preload(:articles)
  end

  @doc """
  Gets a single user.

  Raises `Ecto.NoResultsError` if the User does not exist.

  ## Examples

      iex> get_user!(123)
      %User{}

      iex> get_user!(456)
      ** (Ecto.NoResultsError)

  """
-  def get_user!(id), do: Repo.get!(User, id)
+  def get_user!(id) do
+    User
+    |> Repo.get!(id)
+    |> Repo.preload(:articles)
+  end


  @doc """
  Creates a user.

  ## Examples

      iex> create_user(%{field: value})
      {:ok, %User{}}

      iex> create_user(%{field: bad_value})
      {:error, %Ecto.Changeset{}}

  """
  def create_user(attrs \\ %{}) do
    %User{}
    |> User.changeset(attrs)
    |> Repo.insert()
  end

  @doc """
  Updates a user.

  ## Examples

      iex> update_user(user, %{field: new_value})
      {:ok, %User{}}

      iex> update_user(user, %{field: bad_value})
      {:error, %Ecto.Changeset{}}

  """
  def update_user(%User{} = user, attrs) do
    user
    |> User.changeset(attrs)
    |> Repo.update()
  end

  @doc """
  Deletes a User.

  ## Examples

      iex> delete_user(user)
      {:ok, %User{}}

      iex> delete_user(user)
      {:error, %Ecto.Changeset{}}

  """
  def delete_user(%User{} = user) do
    Repo.delete(user)
  end

  @doc """
  Returns an `%Ecto.Changeset{}` for tracking user changes.

  ## Examples

      iex> change_user(user)
      %Ecto.Changeset{source: %User{}}

  """
  def change_user(%User{} = user) do
    User.changeset(user, %{})
  end

  def authenticate_user(email, plain_text_password) do
    query = from u in User, where: u.email == ^email
    Repo.one(query)
    |> check_password(plain_text_password)
  end
  defp check_password(nil, _), do: {:error, "Incorrect username or password"}
  defp check_password(user, plain_text_password) do
    case Bcrypt.checkpw(plain_text_password, user.password) do
      true -> {:ok, user}
      false -> {:error, "Incorrect username or password"}
    end
  end

  def current_user(conn) do
    Guardian.Plug.current_resource(conn)
  end
end
```

```diff:lib/ex_blog/blog/blog.ex
defmodule ExBlog.Blog do
  @moduledoc """
  The Blog context.
  """

  import Ecto.Query, warn: false
  alias ExBlog.Repo

  alias ExBlog.Blog.Article
+  alias ExBlog.Accounts.User

  @doc """
  Returns the list of articles.

  ## Examples

      iex> list_articles()
      [%Article{}, ...]

  """
  def list_articles do
-    Repo.all(Article)
+    Article
+    |> Repo.all()
+    |> Repo.preload(:user)
  end

  @doc """
  Gets a single article.

  Raises `Ecto.NoResultsError` if the Article does not exist.

  ## Examples

      iex> get_article!(123)
      %Article{}

      iex> get_article!(456)
      ** (Ecto.NoResultsError)

  """
-  def get_article!(id), do: Repo.get!(Article, id)
+  def get_article!(id) do
+    Article
+    |> Repo.get!(id)
+    |> Repo.preload(:user)
+  end

  @doc """
  Creates a article.

  ## Examples

      iex> create_article(%{field: value})
      {:ok, %Article{}}

      iex> create_article(%{field: bad_value})
      {:error, %Ecto.Changeset{}}

  """
-  def create_article(attrs \\ %{}) do
+  def create_article(%User{} = user, attrs \\ %{}) do
    %Article{}
    |> Article.changeset(attrs)
+    |> Ecto.Changeset.put_change(:user_id, user.id)
    |> Repo.insert()
  end

  @doc """
  Updates a article.

  ## Examples

      iex> update_article(article, %{field: new_value})
      {:ok, %Article{}}

      iex> update_article(article, %{field: bad_value})
      {:error, %Ecto.Changeset{}}

  """
  def update_article(%Article{} = article, attrs) do
    article
    |> Article.changeset(attrs)
    |> Repo.update()
  end

  @doc """
  Deletes a Article.

  ## Examples

      iex> delete_article(article)
      {:ok, %Article{}}

      iex> delete_article(article)
      {:error, %Ecto.Changeset{}}

  """
  def delete_article(%Article{} = article) do
    Repo.delete(article)
  end

  @doc """
  Returns an `%Ecto.Changeset{}` for tracking article changes.

  ## Examples

      iex> change_article(article)
      %Ecto.Changeset{source: %Article{}}

  """
  def change_article(%Article{} = article) do
    Article.changeset(article, %{})
  end
end
```

create_articleメソッドを変更したので呼び出し側のarticleコントローラも引数を変更します

```diff:lib/ex_blog_web/controllers/article_controller.ex
  def create(conn, %{"article" => article_params}) do
-    case Blog.create_article(article_params) do
+    case Blog.create_article(Guardian.Plug.current_resource(conn), article_params) do
      {:ok, article} ->
        conn
        |> put_flash(:info, "Article created successfully.")
        |> redirect(to: Routes.article_path(conn, :show, article))

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

```

これでロジック部分でリレーションを反映させることができました
次はビューを変更しましょう

### |> ビューの変更
#### |> layout
```erb:lib/ex_blog_web/templates/layout/app.html.eex
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Hello ExBlog!</title>
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>">
  </head>

  <!-- phoenix.cssが邪魔するので暫定的にbodyに直接style -->
  <body style="margin-top: 0px">
    <header class="header">
      <div class="navbar navbar-dark bg-dark shadow-sm">
        <div class="container d-flex justify-content-between">
          <nav role="navigation">
            <ul class="nav nav-pills pull-right">
              <%= if current_user(@conn) do %>
                <li>
                  <%= link to: Routes.user_path(@conn, :show, current_user(@conn)) do %>
                    <button type="button" class="btn btn-default btn-sm">
                      Name: <b><%= current_user(@conn).name %></b>
                    </button>
                  <% end %>
                </li>
                <li>
                  <%= link to: Routes.session_path(@conn, :delete), method: :delete do %>
                    <button type="button" class="btn btn-default btn-sm">
                      Logout
                    </button>
                  <% end %>
                </li>
              <% else %>
                <li>
                  <%= link to: Routes.session_path(@conn, :new) do %>
                    <button type="button" class="btn btn-default btn-sm">
                      Login
                    </button>
                  <% end %>
                </li>
              <% end %>
            </ul>
          </nav>
        </div>
      </div>
    </header>
    <div class= "container">
      <p class="alert alert-success" role="alert"><%= get_flash(@conn, :success) %></p>
      <p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
      <p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>

      <main role="main">
        <%= render @view_module, @view_template, assigns %>
      </main>

    </div> <!-- /container -->
    <script src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>
```

※Phoenix1.4からデフォルトのcssがbootstrapから[Milligram](https://milligram.io/buttons.html)に変わりました
上記のコードはbootstrap準拠で書いているのでスタイル崩れちゃいます＞＜
気になる人は適宜スタイル修正するかbootstrap入れるかしてみてください
ただし単純にprev/repo/static/app.cssを置き換えるだけだと、webpackが自動でデフォルトに書き直す処理が入るのでダメみたいですね
今回は見た目後回しでいいと思うので、とりあえず先にすすみましょう

#### |> page/index
urlに打ち込むのは面倒なので、ログイン/ユーザ登録などへのボタンを追加

```erb:lib/ex_blog_web/templates/page/index.html.eex
<div class="jumbotron">
  <h2>Simple blog by Phoenix</h2>
  <%= unless current_user(@conn) do %>
    <p class="lead">
      <%= link to: Routes.user_path(@conn, :new) do %>
        <button type="button" class="btn btn-primary">
          Sign in!
        </button>
      <% end %>
    </p>
  <% end %>
</div>
```

```elixir:lib/ex_blog_web/views/page_view.ex
defmodule ExBlogWeb.PageView do
  use ExBlogWeb, :view
  alias ExBlog.Accounts
  def current_user(conn) do
    Accounts.current_user(conn)
  end
end
```
#### |> user
ログインしているuser自身のリソースのみEdit, Deleteリンクが出るようにしましょう

```erb:lib/ex_blog_web/templates/user/show.html.eex
<h1>Show User</h1>

<ul>

  <li>
    <strong>Name:</strong>
    <%= @user.name %>
  </li>

  <li>
    <strong>Email:</strong>
    <%= @user.email %>
  </li>

</ul>

<%= if @user.id == current_user(@conn).id do %>
  <span><%= link "Edit", to: Routes.user_path(@conn, :edit, @user) %></span>
<% end %>
<span><%= link "Back", to: Routes.user_path(@conn, :index) %></span>

<h2>Listing Articles</h2>
 <table class="table">
  <thead>
    <tr>
      <th>Title</th>
      <th>Content</th>
       <th></th>
    </tr>
  </thead>
  <tbody>
<%= for article <- @user.articles do %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.content %></td>
       <td class="text-right">
        <span><%= link "Show", to: Routes.article_path(@conn, :show, article), class: "btn btn-default btn-xs" %></span>
        <%= if @user.id == current_user(@conn).id do %>
          <span><%= link "Edit", to: Routes.article_path(@conn, :edit, article), class: "btn btn-default btn-xs" %></span>
          <span><%= link "Delete", to: Routes.article_path(@conn, :delete, article), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %></span>
        <% end %>
      </td>
    </tr>
<% end %>
  </tbody>
</table>
 <%= if @user.id == current_user(@conn).id do %>
  <span><%= link "New Article", to: Routes.article_path(@conn, :new) %></span>
<% end %>
```

```elixir:lib/ex_blog_web/views/user_view.ex
defmodule ExBlogWeb.UserView do
  use ExBlogWeb, :view
  alias ExBlog.Accounts
  def current_user(conn) do
    Accounts.current_user(conn)
  end
end
```

#### |> article
リレーションを反映させたことで`@article.user.name`のように対応するuserの情報を取得することができるようになりました
またリレーションをたどることで、articleの所有しているユーザが分かるので、userは自分自身が所有しているarticleのみを削除＆編集ボタン表示するようにします

```erb:lib/ex_blog_web/templates/article/index.html.eex
<h2>Listing Articles</h2>

<table class="table">
  <thead>
    <tr>
      <th>User</th>
      <th>Title</th>
      <th>Content</th>

      <th></th>
    </tr>
  </thead>
  <tbody>
<%= for article <- @articles do %>
    <tr>
      <td><%= article.user.name %></td>
      <td><%= article.title %></td>
      <td><%= article.content %></td>

      <td class="text-right">
        <span><%= link "Show", to: Routes.article_path(@conn, :show, article), class: "btn btn-default btn-xs" %></span>
        <%= if article.user.id == current_user(@conn).id do %>
          <span><%= link "Edit", to: Routes.article_path(@conn, :edit, article), class: "btn btn-default btn-xs" %></span>
          <span><%= link "Delete", to: Routes.article_path(@conn, :delete, article), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %></span>
        <% end %>
      </td>
    </tr>
<% end %>
  </tbody>
</table>

<span><%= link "New Article", to: Routes.article_path(@conn, :new) %></span>
```

```erb:lib/ex_blog_web/templates/article/show.html.eex
<h2>Show Article</h2>

<ul>

  <li>
    <strong>User:</strong>
    <%= @article.user.name %>
  </li>

  <li>
    <strong>Title:</strong>
    <%= @article.title %>
  </li>

  <li>
    <strong>Content:</strong>
    <%= @article.content %>
  </li>

</ul>
<%= if @article.user.id == current_user(@conn).id do %>
  <span><%= link "Edit", to: Routes.article_path(@conn, :edit, @article) %></span>
<% end %>
<span><%= link "Back", to: Routes.article_path(@conn, :index) %></span>
```

```elixir:lib/ex_blog_web/views/article_view.ex
defmodule ExBlogWeb.ArticleView do
  use ExBlogWeb, :view
  alias ExBlog.Accounts
  def current_user(conn) do
    Accounts.current_user(conn)
  end
end
```

ここまでで画面を見てみましょう
koyoユーザでログインし`localhost:4000/articles`に行きます
各種リンクボタンがあり、また`KOYO'S PAGE`を見るとログインユーザ名を反映して動的に描画されていることが分かります

![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/8a37a625-5856-88a1-0798-6e63ebd49c27.png)

さてnew articleをクリックして適当にarticleを生成します
このフォームにはuser_idを入力する部分はありませんが、先ほど実装したようにログインユーザのidが自動で入るようになっています
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/ee19edaa-8792-b9c3-d0ce-3489c3c7e91f.png)

submitしてもう一度戻ると以下のようにuser名が自動登録され、また自分が所有しているarticleのみEdit, Deleteリンクが生成されていますね
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/be0e950d-9712-421d-f8be-483fe977efab.png)

さて、今は画面側で表示していないだけなので、直接URL叩けば自分が所有していないarticleを操作できます
試してみましょう
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/974c3f03-8e13-876e-06c2-14be4f1d8216.png)
urlからsampleくんのidは1っぽいですね
`localhost:4000/articles/1/edit`とすればeditできそうなので、やってみたらできました
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/8be3efcb-6632-95cc-8288-ebb0ba91d01d.png)
これはセキュリティ的に大変良くないので、コントローラ側で権限があるのかをチェックする必要がありますね
これは先ほどuserリソースでも同じことしているのでおさらいです

## |> 自分自身が所有しているarticleのみ編集できるようにする
```elixir:lib/ex_blog_web/controllers/article_controller.ex
defmodule ExBlogWeb.ArticleController do
  use ExBlogWeb, :controller

  alias ExBlog.Blog
  alias ExBlog.Blog.Article
  alias ExBlog.Accounts
  alias ExBlog.Accounts.Guardian

  plug :is_authorized when action in [:edit, :update, :delete]

  def index(conn, _params) do
    articles = Blog.list_articles()
    render(conn, "index.html", articles: articles)
  end

  def new(conn, _params) do
    changeset = Blog.change_article(%Article{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"article" => article_params}) do
    case Blog.create_article(Guardian.Plug.current_resource(conn), article_params) do
      {:ok, article} ->
        conn
        |> put_flash(:info, "Article created successfully.")
        |> redirect(to: Routes.article_path(conn, :show, article))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    article = Blog.get_article!(id)
    render(conn, "show.html", article: article)
  end

  def edit(conn, _) do
    article = conn.assigns.article
    changeset = Blog.change_article(article)
    render(conn, "edit.html", article: article, changeset: changeset)
  end

  def update(conn, %{"article" => article_params}) do
    article = conn.assigns.article

    case Blog.update_article(article, article_params) do
      {:ok, article} ->
        conn
        |> put_flash(:info, "Article updated successfully.")
        |> redirect(to: Routes.article_path(conn, :show, article))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "edit.html", article: article, changeset: changeset)
    end
  end

  def delete(conn, _) do
    article = conn.assigns.article
    {:ok, _article} = Blog.delete_article(article)

    conn
    |> put_flash(:info, "Article deleted successfully.")
    |> redirect(to: Routes.article_path(conn, :index))
  end

  # Current_user can access only own resources
  # Check current_user's id match article.user.id
  defp is_authorized(conn, _) do
    current_user = Accounts.current_user(conn)
    article = Blog.get_article!(conn.params["id"])
    if current_user.id == article.user.id do
      assign(conn, :article, article)
    else
      conn
      |> put_flash(:error, "You can't modify that page")
      |> redirect(to: Routes.page_path(conn, :index))
      |> halt()
    end
  end
end
```
さてもう一度`localhost:4000/articles/1/edit`を試してみると
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/f913e145-793d-0d77-bf74-e6d25dc01521.png)
ちゃんと制限されましたね！

## |> user/showに所有しているarticleの一覧を表示
これで最後です！
user/showのページに自分が所有しているarticleの一覧を出してみましょう
とはいえ簡単でuser/show.html.eexに以下を追加するだけです

```erb:lib/ex_blog_web/templates/user/show.html.eex

<h2>Listing Articles</h2>
 <table class="table">
  <thead>
    <tr>
      <th>Title</th>
      <th>Content</th>
       <th></th>
    </tr>
  </thead>
  <tbody>
<%= for article <- @user.articles do %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.content %></td>
       <td class="text-right">
        <span><%= link "Show", to: Routes.article_path(@conn, :show, article), class: "btn btn-default btn-xs" %></span>
        <%= if @user.id == current_user(@conn).id do %>
          <span><%= link "Edit", to: Routes.article_path(@conn, :edit, article), class: "btn btn-default btn-xs" %></span>
          <span><%= link "Delete", to: Routes.article_path(@conn, :delete, article), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %></span>
        <% end %>
      </td>
    </tr>
<% end %>
  </tbody>
</table>
 <%= if @user.id == current_user(@conn).id do %>
  <span><%= link "New Article", to: Routes.article_path(@conn, :new) %></span>
<% end %>
```

koyoユーザはhoge, hoge1, hoge2のarticleリソースを持っていて、sampleユーザは別のhogeのarticleリソースを持っていますね
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/59749eb3-8552-002e-db61-02612d0a5528.png)

KOYO's PAGEリンクをクリックしてuser/showに遷移すると
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/aa7cc669-990d-036a-2644-111df9d8cc4e.png)

koyoユーザが作成したarticleリソースの一覧が表示されています！

・・・これで一通り完成しました！お疲れ様です！
次はこれ以降の学習のヒントを示したいと思います

##|> 追加課題
### |> 自分なりの機能を追加してみる
このチュートリアルで簡単なブログアプリができました
ここまでやれば後は[Phoenix](https://hexdocs.pm/phoenix/up_and_running.html)公式ドキュメントを（英語苦手な人はGoogle翻訳駆使しながら）読んだり、EctoやGurdianのドキュメント読めば大抵のことはできるのではないでしょうか！（例えばarticleに対するcommentリソースを実装してみるといいかもしれないですね）
ぜひ自分のアイデアを実現させてみてください

### |> テスト書いてみる
実運用ではテストは必須です！（というより、今回は説明のためテスト書かずに実装しましたが、慣れてきたらテストを先に書く**TDD**でやった方がいいです）
Elixirには[ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html)というテストフレームワークが標準装備なので、ドキュメント読みながら実装してみましょう！
ちなみに`mix phx.gen.html`で生成したコードにはすでにテストが自動生成されているので、まずはそれを参考にしてみるといいと思います

### |> Gigalixirにデプロイしてみる
なんと！Elixirには専門のPaasである[Gigalixir](https://gigalixir.com/)が存在します
使い勝手はHerokuみたいな感じです
ちょっと設定すればデプロイできるので、piacereさんの以下の資料を読んでチャレンジしてみてください！

[【Gigalixir編①】Elixir／Phoenix本番リリース： 初期PJリリースまで](https://qiita.com/piacere_ex/items/1a9cbcc740ca3707eaec)

# |> 参考
Phoenix1.3バージョンですが、githubのコードとGigalixirにデプロイしたアプリを置いておきますね！（Gigalixirの方は無料だと1アプリまでなので、そのうち消します・・・リンク切れていたらごめんなさい＞＜）
テストもちょっとだけ書いたので参考になるかもしれません

ちなみに1.3では`page_path(...)`と記述していたところが1.4では`Routes.page_path(...)`というようにRoutesというモジュール名を明示的に書くように変更されているので、バージョンをまたぐ場合は適宜読み替えてください

|>[Github](https://github.com/koyo-miyamura/ex_blog_practice)
|>[ex-blog.gigalixirapp.com](https://ex-blog.gigalixirapp.com/)

# |> まとめ
Elixirのコードは可読性高くまとまりますね！
Phoenixを使えばRailsと遜色ないスピードで開発できて、しかもRailsの悩みである性能問題をある程度解消できます
おまけにアクターモデル由来の軽量プロセスにより耐障害性も高いんです（エッヘン）

このように単一CPU性能の向上を待たずして、メニーコアの性能を生かし切る可能性を秘めたElixir（Phoenix）が新たなトレンドになる日も近いかもしれません
是非触ってみてください！

次回は[hykw](https://qiita.com/hykw)さんの記事です！