[有料級]　Rails7(Turbo), Docker, Bootstrap5を使ったtodoリストの作り方第2章-1(モーダル画面作成編)

## 前回のあらすじ
ここまでみていただきありがとうございます！
前回まででTodoリストの作成が終わりました！
[[有料級]　Rails7(Turbo), Docker, Bootstrap5を使ったtodoリストの作り方第1章-5(Todoリスト削除編)](https://qiita.com/streasure0426/items/e103a62dc91e619a06e2)

今回からはTurboを使ってさらにTodoリストを見やすくしたいと思います。
## 事前準備
Dockerを一度止めている方はこちらのコマンドでDockerを起動し、コンテナに入りましょう。
``` bash
docker-compose up -d
docker-compose exec app bash
```

## モーダルの作成
### コントローラーの作成
まずはモーダルのコントローラーを作成します。
コントローラーを使うことによって非同期でモーダルの操作を行うことができます。
``` bash
 rails g stimulus modal
```

コマンドを入力したら次のようなファイルが作成されるはずです。
``` js:app/javascript/controllers/modal_controller.js
import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="modal"
export default class extends Controller {
  connect() {
  }
}

```

このコントローラーの中に以下の機能を書きます。
- モーダルを生成して表示する
- 保存が成功した時にモーダルを自動で閉じる

実際に上記の機能を加えると次のようなコードになります
``` js:app/javascript/controllers/modal_controller.js
import { Controller } from "@hotwired/stimulus"
import { Modal } from "bootstrap"

export default class extends Controller {
  connect() {
    this.modal = new Modal(this.element)
    this.modal.show()
  }
  close(event) {
    if (event.detail.success) {
      this.modal.hide()
    }
  }
}
```
これでコントローラーの作成は完了です。

### モーダル画面の作成
モーダルの画面を作成していきます。
まずはファイルを作成したいので以下のコマンドを入力してください。
``` bash
mkdir app/views/application
touch app/views/application/_modal.html.slim
```
このコマンドでapplicationディレクトリとモーダルのファイルが生成されました。

次にモーダルファイルの編集をします。
``` slim:app/views/application/_modal.html.slim
= turbo_frame_tag "modal" do
  .modal.fade data-controller="modal"
    .modal-dialog
      .modal-content
        = yield
```
コードの説明をします。
`turbo_frame_tag "modal"`："modal"という名前のフレームワークが作成されます。
`data-controller="modal"`：先ほど作成したmodal_controller.jsを接続する役割を担っています。
これでモーダルの共通ファイルができました。

## 新規作成画面のモーダル化
新規作成画面をモーダルにしていきます。
``` diff_slim: app/views/todos/new.html.slim
+ = render "modal" do
+ .modal-header
+   h5.modal-title
+     | 新規作成
+   button.btn-close type="button" data-bs-dismiss="modal" aria-label="Close"

+ .modal-body
    = form_for(@todo) do |form|
      .form-group
        = form.label :タイトル
        = form.text_field :title, class: 'form-control'
      .form-group
        = form.label :内容
        = form.text_area :description, class: 'form-control'
      = form.submit '作成', class: 'btn btn-primary mt-3'
      = link_to "戻る", todos_path, class: 'btn btn-secondary mt-3'
```
コードの説明をします
`data-bs-dismiss="modal"`：モーダルを閉じるメソッドを設定しています。

これで新規作成画面のモーダル化が完了しました。

## 編集画面のモーダル化
編集画面をモーダルにしていきます。
``` diff_slim: app/views/todos/edit.html.slim
+ = render "modal" do
+ .modal-header
+   h5.modal-title
+     | Todo編集
+   button.btn-close type="button" data-bs-dismiss="modal" aria-label="Close"

+ .modal-body
    = form_for(@todo) do |form|
      .form-group
        = form.label :タイトル
        = form.text_field :title, class: 'form-control'
      .form-group
        = form.label :内容
        = form.text_area :description, class: 'form-control'
      = form.submit '更新', class: 'btn btn-success mt-3'
      = link_to "戻る", todos_path, class: 'btn btn-secondary mt-3'
```
これで編集画面のモーダル化が完了しました。
最後にモーダルを表示できるようにapp/views/layouts/application.html.slimにコードを追加します。

``` diff_slim:app/views/layouts/application.html.slim
doctype html
html
  head
    title
      | Myapp
    meta[name="viewport" content="width=device-width,initial-scale=1"]
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag "application", "data-turbo-track": "reload"
    = javascript_importmap_tags
  body
    = yield
+  = turbo_frame_tag "modal"
```

これで非同期通信でモーダル画面を作成することができました。
実際に表示されているのか検証してみましょう。

## 検証

- まずTodo追加ボタンを押して画面遷移をせずにモーダルが表示されるか試してみましょう。
![スクリーンショット 2023-04-19 18.35.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982962/d65bff10-cc90-48b4-a768-4b7a80a6c7ba.png)
上の画像のようになっていれば成功です。

- xボタンを押して一覧画面に戻るか確かめてみましょう。
一覧画面に戻っていれば成功です。

- 次に編集ボタンを押して画面遷移をせずにモーダルが表示されるか試してみましょう。
![スクリーンショット 2023-04-19 18.37.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982962/3df023fe-88f2-744d-4acc-fb2b7abf8033.png)
上の画像のようになっていれば成功です。

今回はここまで！

次回もお楽しみに！

次回URL予定地