【初心者向け🔰】Ruby on Rails チュートリアル 入門（データ登録画面を作る）

## 概要
初めて Ruby on Rails で Web アプリ開発するための、入門編の記事。
Rails の基礎部分をなるべく絞って解説する。

|手順|記事|
|---|---|
|#1|[Rails の開発環境構築](https://qiita.com/to3izo/items/5d06243998192513bed9)|
|#2|[コントローラ・ビューの基本](https://qiita.com/to3izo/items/697497daf7c4722e98d3)|
|#3|[モデルとマイグレーションの基本](https://qiita.com/to3izo/items/a17a6ce61e0002fd8f5c)|
|#4|[DB のデータを画面に表示する](https://qiita.com/to3izo/items/422e06724f360e1d0d19)|
|#5|**画面から DB にデータを登録する**（今回）|
|#6|[画面から DB のデータをの更新・削除する](https://qiita.com/to3izo/items/a8001c1bbf7919d137ed)|

### 対象
- Ruby on Rails で開発をしてみたい（しなければならない状況になった）方
- HTML/CSS で簡単な Web ページを書いたことがある方
- 「DB」「SQL」という言葉の意味を何となく理解できる方
- 「REST API」や「GET」「POST」などを聞いたことがある方
- Ruby もしくは、その他のオブジェクト指向のプログラミング言語に触れた方
  - 変数、四則演算、if 文、for 文、などは書いたことある
  - クラス、メソッド、インスタンス、などは聞いたことある

### 前提
:::note warn
macOS で作業する前提で書いてます。Windows の方は適宜、読み替えてください🙏
:::

- OS： macOS 13.12.1 "Ventura"
- CPU： Intel
- Ruby： v3.1.3
- SQLite3： v3.39.5
- Bundler： v2.4.9
- Rails： v7.0.4

## 手順（DB のデータを追加する画面を作る）
Rails でデータ登録処理を作る場合、Web アプリのデータ登録時の慣習に従って、アクションは `new`（フォーム入力・エラーチェック） と `create`（データ登録処理） の２つを使って実現する。

### ルーティングを追加する
`new` アクションと `create` アクションのルーティングを追加する。
また、Top コントローラの画面をやめて、Users コントローラの index アクションをトップページに変更するため、このタイミングでルーティングの初期ページ設定も変更する。

```diff_ruby:config/routes.rb
  Rails.application.routes.draw do
+   root "users#index"    # アプリのトップページのアクションを指定
-   get "/", to: "top#index"    # 削除

    get "/users", to: "users#index"
+   get "/users/new", to: "users#new"    # new アクション追加
    get "/users/:id", to: "users#show", as: "user"
+   post "/users", to: "users#create"    # create アクション追加
  end
```
👉 `root "コントローラ名#アクション"` とすることで、このアプリのトップページを指定できる。これは、`get "/"` よりも優先される。

👉不要となった Top コントローラ関連ファイルを削除する

- app/controllers/top_controller.rb
- app/helpers/top_helper.rb
- app/views/top/index.html.erb
- test/controllers/top_controller_test.rb

:::note alert
**注意点** `new` アクションは `show` アクションより前に書くこと。
なぜなら、`/users/:id` の `:id` は任意の文字列が全て対象となるため、 `/users/new` もこれに該当してしまう。
そのため、順序を間違えると常に `show` アクションが先に呼ばれてしまうバグとなる。
:::

### トップページに登録ボタンを追加する
`link_to` に似ている `button_to` ヘルパーで `/users/new` に遷移させるボタンを追加する。

```diff_erb:app/views/users/index.html.erb
   <ul>
     <% @users.each do |user| %>
       <li>
         <%= user.name %>/<%= user.age %>
         <%= link_to '詳細', user_path(user.id) %>
       </li>
     <% end %>
   </ul>

+  <div>
+    <%= button_to "登録", { action: "new" }, method: :get %>
+  </div>
```
👉 `button_to "ボタンラベル", {アクション}, {メソッド}` と指定することで、特定のアクションのルーティングを呼び出す URL を発行できる。

ブラウザで `localhost:3000` にアクセスすると以下の画面になる。
![rails_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/c5cad231-f51e-26e0-09dd-311f643390fb.png)
👉 ルーティングを修正したので、トップページが `Users` コントローラの `index` アクションになっている。また、登録画面がまだ無いが、ボタンを押すと `/users/new` にアクセスする様になっている。

### 登録用のアクションを追加する
コントローラに `new` アクションと `create` アクションを以下の様に追加する。

```diff_ruby:app/controllers/users_controller.rb
  class UsersController < ApplicationController

+   def new
+     @user = User.new
+   end

+   def create
+     @user = User.new(name: params[:user][:name], age: params[:user][:age])
+
+     if @user.save
+       redirect_to @user
+     else
+       render :new, status: :unprocessable_entity
+     end
+   end
  end
```
👉 まず `new` アクションが呼ばれ、画面入力された値を入れる `@user` を用意して画面表示。次に `create` アクションが呼ばれ、入力値を格納したパラメータ（params）をもとに変数を作り直し、`save` メソッドで DB登録を実行する。
👉 Users コントローラで `redirect_to @user` とすると、`/users/{@user.id}` の URL にリダイレクトする（通信処理のヘルパー）
👉 Users コントローラで `render :new` とすると、`app/views/users/new.html.erb` の画面を表示する（レンダリング処理のヘルパー）

### データ入力フォームを作る
`new` アクションの画面テンプレートを作る。ここで、Rails の **「フォームビルダー（form builder）」** というヘルパーを利用する。

```erb:app/views/users/new.html.erb
<h1>New User</h1>

<%= form_with model: @user do |form| %>
  <div>
    <%= form.label :name %><br>
    <%= form.text_field :name %>
  </div>

  <div>
    <%= form.label :age %><br>
    <%= form.text_field :age %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>
```
👉 `form_with` ヘルパーは、フォームをインスタンス化する（ここでは `form` としている）。`form_with` インスタンスには、「label」や「text_field」等のフォーム要素を作るメソッドが用意されている。
👉 `form_with` は、 HTML の `<form action="/users" method="post">` に相当する。
👉 `model: @user` は `new` アクションで作ったインスタンス変数。

### 登録画面が完成

この時点で、トップページから「登録」ボタンで作成した登録画面に遷移できる様になっており、データも登録ができる。
![rails_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/8a189b8a-dede-d09c-bfd5-8aa65aa11a4b.png)

## 手順（画面にバリデーションを追加する）
現在は、入力項目が空でもデータが登録できてしまうので、必須入力を設定するなどチェック機構を追加する。

### 入力内容の取得方法をシンプルにする
登録データのパラメータを生成する部分を、プライベートメソッドにまとめる。
また、パラメータ生成部分を **Strong Parameters（ストロングパラメーターズ）** でまとめる書き方に変更する（項目毎に何度も `params[:user]` と書くのを避ける）。

```diff_ruby:app/controllers/users_controller.rb
  class ArticlesController < ApplicationController

    def create
-     @user = User.new(name: params[:user][:name], age: params[:user][:age])
+     @user = User.new(user_params)
 
      if @user.save
        redirect_to @user
      else
        render :new, status: :unprocessable_entity
      end
    end

+   # ここから下は アクションではなく プライベートメソッド
+   private
+     def user_params
+       params.require(:user).permit(:name, :age)
+     end
  end
```
👉 `name: params[:user][:name], age: params[:user][:age]` が `params.require(:user).permit(:name, :age)` に置き換わる。


### モデルにバリデーションを追加する
`validates` というバリデーションヘルパーを利用し、「名前」と「年齢」のパラメータは必須入力にする。

```diff_ruby:app/models/user.rb
  class User < ApplicationRecord
+     validates :name, presence: true
+     validates :age, presence: true
  end
```
👉 `presence: true` で **"入力必須"** となる。この時点で、画面にはまだ何もエラーメッセージは表示されないが、未入力の場合に登録がストップする状態になっている（`create` アクションの if 文で else 側に処理分岐する）。

### バリデーションエラーを画面に表示する
バリデーションは既に聞いているが、画面には明示されていないので、表示を追加する。

```diff_erb:app/views/users/new.html.erb
   <h1>New User</h1>

   <%= form_with model: @user do |form| %>
     <div>
       <%= form.label :name %><br>
       <%= form.text_field :name %>
+      <% @user.errors.full_messages_for(:name).each do |message| %>
+        <div><%= message %></div>
+      <% end %>
     </div>

     <div>
       <%= form.label :age %><br>
       <%= form.text_field :age %>
+      <% @user.errors.full_messages_for(:age).each do |message| %>
+        <div><%= message %></div>
+      <% end %>
     </div>

     <div>
       <%= form.submit %>
     </div>
   <% end %>
```

### 画面で確認

実際に空の状態で Submit すると、以下の様にデフォルトのエラーメッセージが表示される。
![rails_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/462463cc-1daf-9bb2-c355-a8774911563e.png)

### エラーメッセージを個別に変更する
表示するメッセージを個別で任意に設定したい場合は、モデルのバリデーションの部分に `message` を設定すると、表示内容を変更できる。

```diff_ruby:app/models/user.rb
   class User < ApplicationRecord
-      validates :name, presence: true
+      validates :name, presence: { message: "必須入力です。" }

-      validates :age, presence: true
+      validates :age, presence: { message: "必須入力です。" }
   end
```
👉 他にも、アプリ全体の日本語化や、アプリとしてのデフォルトメッセージの定義などもできるが、今回は割愛する。

## まとめ

- ルーティングに `root` を使うと、トップページ（のアクション）を指定できる
- Rails での登録処理は、`new` アクションと `create` アクションで実現する
- ルーティング設定は、`new` と `show` の順序に注意する
- モデルにバリデーションを設定すると、入力チェックができる
- エラーメッセージはカスタマイズできる