【Ruby on Rails】初学者向け－開発の流れについて④　一覧、新規作成、参照、更新、削除画面機能の追加編vol.1

本記事については簡易的なタスク管理アプリを作成することを前提に、
下記流れのもと、Railsの開発について言及して行きたいと思います。

## Rails開発の流れについて

・Railsプロジェクトの作成とDockerの設定
[【Ruby on Rails】初学者向け－開発の流れについて①　プロジェクトの作成編](https://qiita.com/y-kida/items/2c8634ceb28a93c84bc9 "Qiita Home")

・Gem・DB設定とルーティング
[【Ruby on Rails】初学者向け－開発の流れについて②　Gem・DB設定とルーティング編](https://qiita.com/y-kida/items/1d34bf72a3296579f213 "Qiita Home")

・Bootstrapの導入
[【Ruby on Rails】初学者向け－開発の流れについて③　Bootstrapの導入編](https://qiita.com/y-kida/items/cb3723a344766fcaf15e "Qiita Home")

**・一覧、新規作成、参照、更新、削除画面機能の追加（今回学習するのはこちら）**
・検索機能の追加
・DBやモデル周りの整備
・バリデーション機能追加
・ユーザー認証機能追加

（※ 他追加機能があれば随時記事にしていく予定です）

--------------------------------------------------------
**前提**
・Docker
・Ruby on Rails 7
・Mysql
・BootStrap
・VSCode

-------------------------------------------------------


前回はRailsの画面を装飾するためのBootStrapというGemの導入を行いました。
今回はようやく一覧、新規作成、参照、更新、削除の機能について言及して行きたいと思います。


↓機能の作成方法だけ見たい方は飛ばしていただいても大丈夫です◎

**【前回】**
[【Ruby on Rails】初学者向け－開発の流れについて③　Bootstrapの導入編](https://qiita.com/y-kida/items/cb3723a344766fcaf15e "Qiita Home")

<details><summary><b>前回のおさらい</b></summary>

前回はBootstrapの導入が完了し、無事にレイアウト含め画面の確認ができるようになったというところで終了しました。
ただ、現時点では実際ダミーのデータを一覧に表示している状態であるため、
実際にDBに登録したデータを取得して一覧を表示するようにしていきたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/da8721cc-fd8c-e84d-3938-30c18c3faf25.png)

</details>

<h1>一覧と新規作成機能について</h1>
ルーティングを終え、簡易的に一覧画面を表示できる状態で説明を進めていきます。
ルーティング・コントローラー・ビューの各コードは以下のようになっています。

```config\routes.rb
Rails.application.routes.draw do
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
   root "tasks#index"
end

```
```ruby:app\controllers\tasks_controller.rb
class TasksController < ApplicationController
    def index
    end
end
```
```html:app\views\tasks\index.html.erb
<div class="d-flex align-items-center">
  <h1>タスク一覧</h1>
  <div class="ms-auto">
    <a class="btn btn-outline-dark">新規作成</a>
  </div>
</div>
<h6>期限が過ぎていいないタスク</h6>
<table class="table table-hover tasks__table">
  <thead class="table-primary">
    <tr>
      <th>ID</th>
      <th>タイトル</th>
      <th>内容</th>
      <th>作成日</th>
      <th>期限日</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1</th>
      <td>課題１</td>
      <td>課題１の内容</td>
      <td>2018年4月1日</td>
      <td>2018年4月15日</td>
    </tr>
  </tbody>
</table>
```
---------------------------------------------------------
まず一覧画面内でデータを表示できるように、
DBに実際に値を入れられるように準備を行います。
Ruby on RailsでDBを扱う上で必要になってくるのが、
下記の「マイグレーションファイル」と「モデル」です。

**マイグレーションファイル**
…DB内にテーブルを作成するうえで必要不可欠なファイル。
　ここに作成したいテーブルの内容（カラム名や型の情報など）を記載し、
 　rails db:migrateというコマンドを用いて実行することでDBにその内容を反映できます。

**モデル(model)**
…DBと密接にかかわりがあり、テーブルごとに作成されるファイル。
　ここにテーブル同士の紐づけ等を記載していきます。

----------------------------------------------------------

 下記のコマンドをターミナルで実行して自動的に上記ファイルを作成します。
 こちらモデル名を記載するときに命名規約に注意してください。
```ruby:terminal
docker-compose run web rails generate model <モデル名> <カラム名>:<データ型> <カラム名>:<データ型>

# 記載例
docker-compose run web rails generate model Task title:string explanation:string
```
内容としてはTaskというモデルを作成し、
「title」と「eplanation」カラムをString型で作成するという意味になります。
このコマンドで、自動的にTaskモデルとTaskモデルを設定するためのマイグレーションファイルが作成されます。
```ruby:terminal
# 無事ファイルが作成されると下記のような結果が表示されます
 ✔ Container task-practice-db-1  Running                                    0.0s 
      invoke  active_record
      create    db/migrate/20241025050550_create_tasks.rb
      create    app/models/task.rb
```


まず作成されたマイグレーションファイルは以下です。
ここに追加でカラムの設定を記載していきます。
```ruby:db/migrate/20241025050550_create_tasks.rb
class CreateTasks < ActiveRecord::Migration[7.0]
  def change
    create_table :tasks do |t|
      t.string :title
      t.string :explanation

      # 追加するカラム
      t.date :due_date
      
      t.timestamps
    end
  end
end

```

マイグレーションファイルに項目が追加できたら、
マイグレーションファイルの内容を反映させるために下記コマンドをターミナルで実行します。
```ruby:terminal
docker-compose run web rails db:migrate
```

これでテーブルに対する設定が完了しました。
以降、このテーブルに値を登録するために新規作成画面を作成します。

----------------------------------------------------------

新規作成画面を表示するにあたって、routes.rbのファイルを以下のように変更します。

```ruby:terminal
Rails.application.routes.draw do
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  root "tasks#index"
  get 'tasks', to: 'tasks#index'
  get 'tasks/new', to: 'tasks#new'
  post 'tasks', to: 'tasks#create'
end
```
記載内容の説明は以下です。
**get**
…GETメソッドのこと。このように記載することで
　サーバからデータの取得が可能になります。
**post**
…POSTメソッドのこと。このように記載することで、
　サーバにフォームで入力した情報の送信や、データ更新の内容を送信することができます。
 　新規作成や編集に使用されるメソッドです。

**'tasks/new'と'tasks'**
…ここでURLの指定を行っています。

**to: 'tasks#new'とto: 'tasks#create'**
…指定したURLとリクエストの内容がマッチしたときに、
　どのコントローラーのアクションを呼び出すかという指定を行っています。
　記載例でいうと、「to: 'tasks#new'」でtasks_controller.rbのnewアクションを呼び出すよう
 　指定しており、「to: 'tasks#create'」ではtasks_controller.rbのcreateアクションを
  　呼び出すよう指定しています。

新しくルーティングが行えたので、tasks_controller.rb側にnewアクションとcreateアクションを記載しましょう。

```ruby:app\controllers\tasks_controller.rb
class TasksController < ApplicationController
    def index
    end

    def new
        # この部分のイメージとしてはインスタンス変数の@taskに、Taskの新規データが入る箱を用意する感じです
        @task = Task.new
    end

    def create
        # newメソッドからcreateメソッドにパラメータ（データの送信内容）が送られてくる
        # ここでは「task_params」という変数に入ったデータの送信内容がnewメソッドからcreateメソッドへ送信されてくるという認識
        @task = Task.new(task_params)

        # インスタンス変数@taskに格納されたtask_paramsの内容をsave（保存）する。
        if @task.save
            # 問題なく保存が行えた場合、下記のメッセージを表示する。
          redirect_to tasks_url, notice: '保存が完了しました。'
        else
            # そうでない場合はnew（新規作成画面）をrenderして再表示する
          render :new
        end
    end

    # このprivate以下で書かれた処理は、コントローラ内で定義された他メソッドから呼び出された際に実行されます。
    private

    def task_params
        # パラメータとして送信されてくるデータすべてを受け取るのは、セキュリティ上良くないため
        # 下記のようにパラメータ内のどのデータの受信を許可(permit)するかについて記載する必要がある
        params.require(:task).permit(:title, :explanation, :due_date, :updated_at, :create_at)
    end
end
```

ここまでで内部の処理が行えるようになったため、次に新規作成画面のビューを作成していきます。

新規作成画面と更新画面はほとんど同じ入力フォームを作成しようと思うので、
入力フォーム部分を共通化するために「パーシャル」というものを使って画面を記載していきます。

**パーシャル**
…Railsの開発にて使用される再利用可能なパーツのこと。
　コードの重複を防ぐことができる。
　新規作成画面と更新画面等、類似した入力フォームを作成するため等に用いられる。
 
--------------------------------------------------------------
まず新規作成画面のビューについてですが、new.html.erbというファイルを作成し、以下のように記載します。

```html:app\views\tasks\new.html.erb
<div class="d-flex align-items-center">
    <h1>新規作成画面</h1>
    <div class="ms-auto boards__linkBox">
         <%= link_to '一覧', root_path, class: 'btn btn-outline-dark'%>
    </div>
</div>
<!-- ここでformというパーシャル（部品）のrenderを行う -->
<%= render partial: 'form', locals: { task: @task } %>
```
**render**
…英語でいうと、「提供する」「表示する」「描画する」という意味。
railsではrenderの記載の後に特定のビューやテンプレートを指定して、
それらを画面上に表示することができます。

 
--------------------------------------------------------------------------------
次にnew.html.erbからrenderするパーシャルのファイルを作成し、以下を記載します。
パーシャルの名前を付けるときは名前の前に必ず「_（アンダーバー）」をつけてください。

```html:app\views\tasks\_form.html.erb
<%= form_with model: @task, local: true, data: {turbo: false} do |f| %>
    <div class="mb-3">
        <%= f.label :title, 'タスク名' %>
        <%= f.text_field :title, class: 'form-control'%>
    </div>
   <div class="mb-3">
        <%= f.label :explanation, 'タスク内容' %>
        <%= f.text_area :explanation, class: 'form-control', rows: 10%>
    </div>
    <div class="mb-3">
        <%= f.label :due_date, '期限日' %>
        <%= f.date_field :due_date, class: 'form-control' %>
    </div>
    <div class="mt-3">
        <%= f.submit '登録', class: 'btn btn primary' %>
    </div>
</div>
<% end %>
```

**form_with**
…Railsでフォームを作成するためのヘルパーメソッド。
　モデルの自動検出を行うことができ、新規のデータか既存のデータかを判断することができる。
```html:app\views\tasks\_form.html.erb
<%= form_with model: @task, local: true, data: {turbo: false} do |f| %>
```
**model: @task**
インスタンス変数@taskに値が入るのが前提になる。
この記述で@taskの新規作成・更新のため適切なURLに送信することができる。

**local: true**
…form_withのオプションの一つ。
　フォーム送信がJavaScriptではなく、ブラウザのデフォルトの動作（ページ全体のリロード）によって処理される。

 **data:{turbo: false}**
 …こちらも上記のlocal: true同様　フォーム送信がJavaScriptではなく、ブラウザのデフォルトの動作（ページ全体のリロード）によって処理されるようにするための記載。


----------------------------------------------------------------------------------------------
ここまで完了したら、一覧画面にて登録したデータが表示されるようにindex.html.erbと
tasks_controller.rbを編集します

```ruby:app\controllers\tasks_controller.rb
#~~~~~~~(省略)~~~~~~~~
    def index
        @tasks = Task.all
    end
#~~~~~~~(省略)~~~~~~~~
```

**@tasks = Task.all**
この記述はindexアクションに入った際
変数@tasksの中にTaskモデルからデータをすべて取ってくるという記述です。

```html:app\views\tasks\index.html.erb
<div class="d-flex align-items-center">
  <h1>タスク一覧</h1>
  <div class="ms-auto">
    <%= link_to '新規作成', tasks_new_path, class: 'btn btn-outline-dark'%>
  </div>
</div>
<h6>期限が過ぎていないタスク</h6>
<table class="table table-hover tasks__table">
  <thead class="table-primary">
    <tr>
      <th>ID</th>
      <th>タイトル</th>
      <th>内容</th>
      <th>作成日</th>
      <th>期限日</th>
    </tr>
  </thead>
  <tbody>
  <!-- 繰り返し処理で@tasksの中身を１つずつ取り出して表示する -->
    <% @tasks.each do |task| %>
      <tr>
        <td><%= task.id %></td>
        <td><%= task.title %></td>
        <td><%= task.explanation %></td>
        <td><%= task.created_at %></td>
        <td><%= task.due_date %></td>
      </tr>
    <% end %>
  </tbody>
</table>
    
```
新規作成画面で登録したデータが一覧画面で表示できるかを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/5ed36da5-fa22-52d2-af3d-28c514ab0270.png)
（テストデータとしていくつか入力しており、バリデーションもかけていないので一部の項目が空になっていますが、バリデーションについては今後記載していきます。）

ここまでで単純な登録が行える確認ができました。

次の記事ではこの登録したデータの編集・削除の処理についてまとめていきます。