Phoenixで論理削除②：削除UIのトグル化

[Elixir Digitalization Implementors／fukuoka.ex／kokura.ex](https://fukuokaex.connpass.com/)のpiacereです
ご覧いただいて、ありがとうございます :bow:

[前回は、Phoenixのphx.gen.html／phx.gen.jsonで生成されるDBアクセッサの「論理削除」を実装](https://qiita.com/piacerex/items/8caec77c322be11ba8ea)したので、今回は、削除UIの論理削除トグル化の対応を行います

内容が、面白かったり、役に立ったら、「LGTM」よろしくお願いします :wink:

<h3>:ocean::ocean::ocean: Advent Calendar、fukuoka.ex1位、Elixir2位達成ヽ(=´▽`=)ﾉ :ocean::ocean::ocean:</h3>

fukuoka.ex Advent Calendar、Webテクノロジーカテゴリで堂々1位 … 各コラムぜひお読みください
https://qiita.com/advent-calendar/2020/fukuokaex
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/8a22a81f-2917-6072-10bd-525e0fc24b75.png)](https://qiita.com/advent-calendar/2020/neosvr_reso)

そして、プログラミング言語カテゴリは、1位がRust、2位がElixir、3位がGoとモダン言語揃い踏みでのトップ3、熱いネー:laughing:
https://qiita.com/advent-calendar/2020/elixir
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/ea185203-c525-c778-dc10-6d2ecc391616.png)](https://qiita.com/advent-calendar/2020/elixir)

# 本コラムの検証環境

本コラムは、以下環境で検証しています（Windowsで実施していますが、Linuxやmacでも動作する想定です）

- Windows 10
- Elixir 1.11.3 　 　　　 ※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/6714e1440e3f25fb46a1#%E4%BA%8B%E5%89%8D%E6%BA%96%E5%82%99elixir%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>
- Phoenix 1.5.7　　　　※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/b7787580fce5f148242f#phoenix%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>
- PostgreSQL 10.1 　　 ※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/a7558adc6856e3577dc6#postgresql%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>

# 削除UIの論理削除対応

一覧UIのDeleteリンクが、前回の対応により、物理削除から、論理削除に変更されていますが、一度Deleteした後は、論理削除状態を解除して、元に戻すことができないUIになっています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/5b148298-dee8-2b39-2ff1-03ea9bf44473.png)

これを、論理削除状態をトグル化するために、コントローラを改修します

改修前のコントローラは、以下の通りです

```elixir:lib/basic_web/controllers/post_controller.ex
defmodule BasicWeb.PostController do
  use BasicWeb, :controller
…
  def delete(conn, %{"id" => id}) do
    post = Posts.get_post!(id)
    {:ok, _post} = Posts.delete_post(post)

    conn
    |> put_flash(:info, "Post deleted successfully.")
    |> redirect(to: Routes.post_path(conn, :index))
  end
…
```

これを以下のように、対象データの論理削除状態で、呼び出す関数と、実行後のメッセージをスイッチするように改修します

```elixir:lib/basic_web/controllers/post_controller.ex
  def delete(conn, %{"id" => id}) do
    post = Posts.get_post!(id)
#    {:ok, _post} = Posts.delete_post(post)  # Comment-out here

    # Add start
    action = case post.deleted_at do
      nil -> %{ target: "deleted",         func: &Posts.delete_post/1 }
      _   -> %{ target: "delete restored", func: &Posts.restore_delete_post/1 }
    end
    {:ok, _post} = action.func.( post )
    # Add end

    conn
#    |> put_flash(:info, "Post deleted successfully.")  # Comment-out here
    |> put_flash(:info, "Post #{ action.target } successfully.")  # Add here
    |> redirect(to: Routes.post_path(conn, :index))
  end
```

一覧UIのDeleteリンク文言も、論理削除状態でスイッチするようにします

```elixir:lib/basic_web/templates/post/index.html.eex
…
<%= for post <- @posts do %>
    <% logical_delete = if post.deleted_at == nil, do: "Delete", else: "Restore"  # Add here %>
    <tr>
      <td>
        <span><%= link "Show", to: Routes.post_path(@conn, :show, post) %></span>
        <span><%= link "Edit", to: Routes.post_path(@conn, :edit, post) %></span>
        <!-- <span> --><%= # Comment-out after link "Delete", to: Routes.post_path(@conn, :delete, post), method: :delete, data: [confirm: "Are you sure?"] %><!-- </span> -->
        <span><%= link logical_delete, to: Routes.post_path(@conn, :delete, post), method: :delete, data: [confirm: "Are you sure?"] %></span>  <!-- Add here -->
      </td>
    </tr>
<% end %>
…
```

これで、Deleteリンクをクリックすると、下記の通り、deleted_atに現在日時（UTC）が入り、DeleteリンクがRestoreリンクにスイッチするようになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/676d518b-fceb-3cde-c227-46a096c041ec.png)

Restoreリンクをクリックすると、deleted_atが空（nil）になり、RestoreリンクがDeleteリンクに戻ります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/725106b1-27af-6c14-e3a8-b33043d691fa.png)

# 最後に

今回は、削除UIの論理削除トグル化を行いました

Elixir開発の実務でも良く出てくるテクニックなので、覚えておきましょう

[次回は、一覧／個別表示UIでの論理削除時グレーアウト表示切り替え](https://qiita.com/piacerex/items/c02cdecfe160d2fd0fb3)を行います

# p.s.このコラムが、面白かったり、役に立ったら…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/67568d54-6584-ad33-77c7-b3b3afe70287.png) や ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/f5b819ef-d655-ef72-294c-b1a9d2c5b563.png) にて、どうぞ応援よろしくお願いします:bow: