【Ruby on Rails】初学者向け－開発の流れについて⑥　DBやモデル周りの整備 & バリデーション機能追加

## 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")

・一覧、新規作成、参照、更新、削除画面機能の追加vol.1
[【Ruby on Rails】初学者向け－開発の流れについて④　一覧、新規作成、参照、更新、削除画面機能の追加vol.1](https://qiita.com/y-kida/items/2d5edbe3be1cd7b7289c "Qiita Home")

・一覧、新規作成、参照、更新、削除画面機能の追加vol.2
[【Ruby on Rails】初学者向け－開発の流れについて④　一覧、新規作成、参照、更新、削除画面機能の追加vol.2](https://qiita.com/y-kida/items/ec0a89bf4c10d3c66e7a "Qiita Home")

・検索機能の追加（今回学習するのはこちら）
[【Ruby on Rails】初学者向け－開発の流れについて⑤　検索機能の追加](https://qiita.com/y-kida/items/721ad89ed3a4a9704997 "Qiita Home")

**・DBやモデル周りの整備 & バリデーション機能追加（今回学習するのはこちら）**
・ユーザー認証機能追加

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

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

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

**前回のおさらい**
前回は一覧画面にて完全一致・部分一致の検索を行えるようにしました。
次はようやくモデルを触ってみます。

<h1>DBやモデル周りの整備</h1>
まずモデルについて改めておさらいしましょう。
**モデル**
…テーブルとの結びつきが強いファイルです。
　各テーブルの関係を記述したり、各項目の設定を記述することができます。

 説明のみだとイメージが沸きづらいと思うので、これからそのモデルを使用した一例を書いてみようと思います。

 **バリデーション**
 …値が入力されているか、また、入力値が指定した形式になっているかをチェックするためのものです。
 　ざっくりチェックできる種類は以下です。
　**・必須項目**（入力されているかどうかのチェック）
 　**・形式**（電話番号のハイフン（-）の有無や、アドレスのフォーマットのチェック）
 　**・長さ**（文字列が何文字までか指定できる）
 　**・数値の範囲**（数値はもちろん、日付の範囲もチェックできる）
　 **・一意であるかどうかの確認**（既存のデータと同じものを登録しないようにする）

これらのチェックを行うことでデータの不備や不整合によるエラーが発生しづらくなるという利点があります。

  今回はタスク登録・編集の際にこれらのチェックを適用するよう処理をモデルに追記していきます。
 
--------------------------------------

まず、下記のように記載します。

```ruby:app\models\task.rb
class Task < ApplicationRecord
    validates :title, presence: true, length: { maximum: 20 }
    validates :explanation, presence: true, length: { maximum: 100 }
    
    validate :due_date_check

    private
    
    def due_date_check
        if due_date.present? && due_date < Date.today
          errors.add(:due_date, "は現在の日付以降でなければなりません")
        end
    end
end
```
まず、上記に記載したバリデーションについて説明していきます。

**validates <:カラム名>**
…このカラムにバリデーションチェックをかけるよという宣言。
　後続にそのバリデーションチェックの内容を設定することができる。

**presence: true**
…入力値が存在していればtrueを返す。存在しなければfalseを返し、エラーを発生させる。

**validates <:メソッド名>**
…バリデーションをかけるにあたって複雑な処理を記載したい場合には、
　メソッド名を設定し、「private」の記述の後にメソッドの内容を記載する。

モデルのみバリデーションチェックの記載をした状態だと、保存ができないだけで
まだ入力エラーのメッセージを発生させることができません。
後述で、バリデーションでfalseが返ってきたときのエラーメッセージの部品と、
それらを表示するためのコントローラーの処理を作成していきます。

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

初めにエラーメッセージを表示したいビューに以下を記載します。
今回はまず新規作成画面でのバリデーションチェックを実装したいので、_form.html.erb内で
エラーメッセージの部品をrenderするように記載します。
```html:app\views\tasks\_form.html.erb
<%= form_with model: @task, local: true, data: {turbo: false} do |f| %>
    <!--追記-->
    <%= render 'shared/error_messages' %>
    <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>
<% end %>
```

次にエラーメッセージの部品となるapp\views\shared\_error_message.html.erbを作成します。
 パーシャルとして扱うのでファイル名の頭に「_(アンダーバー)」を付けます。

 ```html:app\views\shared\_error_message.html.erb
 <%if flash[:error_messages] %>
  <div class="alert alert-danger">
    <ul>
      <% flash[:error_messages].each do |msg| %>
      <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>
```
**flash[:error_messages]**
…フラッシュメッセージの一つ。一時的にここにエラーメッセージが保存されます。

**.each do |msg|**
…一時的に保存したエラーメッセージの中身を１つずつ取り出す処理です。

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

次にそのパーシャルを呼び出すためのコントローラーの処理を記載します。
```ruby:app\controllers\tasks_controller.rb
    def create
        @task = Task.new(task_params)
        if @task.save
            redirect_to tasks_url, notice: '保存が完了しました。'
        else
            # 追記
            flash[:error_messages] = @task.errors.full_messages
            render :new
        end
    end
```

**flash[:error_messages] = @task.errors.full_messages**
…ビューにも記載しておいたflash[:error_messages]の中に@task.errors.full_messagesを代入します。



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


このままでもエラーメッセージが表示されますが、
デフォルトで英語が設定されているので、日本語に設定し直す必要があります。

そしてこのメッセージ内に入る日本語をja.ymlで設定します。
未だファイルを作成していない場合はconfig\locales\ja.ymlを作成してください。
まずこのja.ymlについて説明します。
**ja.yml**
…日本語に翻訳変換したり、ローカライズを定義するためのものです。
　階層構造になっており、例えばどの画面のどのカラムがどういった日本語かを設定できる

**ローカライズ**
…ソフトウェアやコンテンツを特定の地域や文化に適応させることです。

このプログラムにおけるja.ymlの例は以下です。

```yml:config\locales\ja.yml
ja:
  activerecord:
    models:
      task: タスク
    attributes:
      task:
        title: タイトル
        explanation: 説明
        due_date: 期限日
    errors:
      messages:
        blank: "を入力してください"
        too_long: "は%{count}文字以内で入力してください"
        greater_than_or_equal_to: "は現在の日付以降でなければなりません"
```

またこのja.ymlを使用するためにconfig\application.rbにコードを追記する必要があります。

```ruby:config\application.rb
require_relative "boot"

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module App
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.0
    
    # 下記の一行を追記
    config.i18n.default_locale = :ja
    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")

    # Don't generate system test files.
    config.generators.system_tests = nil
  end
end
```

これでエラーメッセージを表示してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/28d047b4-5dae-3705-3a71-76ceccf395f0.png)

このようにメッセージが表示されたらバリデーションチェックの完成です。