Ratyを使ったレビュー機能 バリデーションエラーの表示方法

#実装内容
**Bootstrap4**では、サーバーサイドでチェックした入力エラーのメッセージを表示するための`「invalid-feedback」`**クラス**が用意されており、項目ごとに分かりやすく表示されるようになっています。

しかし、入力欄に`<input>タグ`を使用していない場合、このエラーメッセージは表示されません、、(自分の場合、**Raty**を使った`レビュー機能`で起こりました、、)

この問題に遭遇し参考記事を探してみたのですが、該当する記事を見つけることができなかったこともあり、備忘録も兼ねて紹介しています。

#処理全体の流れ

1. 三項演算子を使用して適切なクラスの付与
1. styleの修正
1. エラーメッセージ表示用のdivタグ作成

#完成形はこちら
###Before
[![Image from Gyazo](https://i.gyazo.com/fc83740cabb77c8dae1794b2091d04f8.png)](https://gyazo.com/fc83740cabb77c8dae1794b2091d04f8)
###After
[![Image from Gyazo](https://i.gyazo.com/0969b38de369eea9e5aefb6cd023d00d.png)](https://gyazo.com/0969b38de369eea9e5aefb6cd023d00d)
###入力後
[![Image from Gyazo](https://i.gyazo.com/904d7e1cd3fd405731959b0f526ed249.png)](https://gyazo.com/904d7e1cd3fd405731959b0f526ed249)

#環境
`macOS Big Sur 11.2.3`
`ruby: 2.7.2`
`rails: 6.1.3`
`jQuery`
`テンプレートエンジン: slim`
`レイアウト: bootstrap4`

#前提

- gem bootstrap4 と Ratyの導入は省いております

#修正前のviewファイル
まず、修正前のコードを御覧ください。

```app/views/travel_records/new.html.slim
= simple_form_for @travel_record do |f|
 = render 'layouts/error_messages', model: f.object
・
・
・
　　#star
  　　= f.label :'オススメ度【必須】', required: false
  　　.d-flex
    　　= f.hidden_field :review, id: :review_star
　　= render 'shared/star' 
```
レビュー機能のため、 カラム名を`review`としています。
Ratyの動作に必要なjsコードはパーシャル化し、`= render 'shared/star' `で呼び出しています。

また、バリデーションは`validates :review, presence: true`とし、入力がない場合にエラーを表示させるようにしています。


#修正後のviewファイル
こちらが完成形のコードになります。
※スタイル適用時にレビュー星を枠で囲って表示するため、コードの記述順を変更しています。

```app/views/travel_records/new.html.slim
= simple_form_for @travel_record do |f|
 = render 'layouts/error_messages', model: f.object
・
・
・
  = f.label :'オススメ度【必須】', required: false
  - is_error = f.object.errors[:review].present? 
  #star class=(is_error ? 'form-control is-invalid' : 'form-control is-valid' if @travel_record.review? || is_error)
    .d-flex
      = f.hidden_field :review, id: :review_star
      = render 'shared/star', show_raty: 'new'
  div class=("invalid-feedback #{f.object.errors[:review].present? ? 'd-block' : 'd-none'}")
    | オススメ度を入力してください
```

###エラーメッセージのファイル

```app/views/layouts/_error_messages.html.slim
- if model.errors.any?
 - model.errors.full_messages.each do | error_message |
  .alert.alert-danger.alert-dismissible.mb-2 role="alert"
    button type="button" class="close" data-dismiss="alert"
      span aria-hidden="true" &times;
      span.sr-only close
    = error_message
```

それでは順を追って説明いたします。

##赤枠の表示

まず初めに、エラー時に表示される赤枠の実装から行なっていきます。

```app/views/travel_records/new.html.slim
- is_error = f.object.errors[:review].present? # コードが重複しているため、変数に格納
#star class=(is_error ? 'form-control is-invalid' : 'form-control is-valid' if @travel_record.review? || is_error)
```

**赤枠を表示させる**には**bootstrapクラス**の`form-control`と`is-invalid`が必要になり、入力があった場合、**緑枠を表示させる**ため、`form-control`と`is-valid`が必要になります。

また、**入力の有無**で表示を切り替えるため、**三項演算子**を使用して条件によって適切なクラスを付与するようにしています。

まず、三項演算子でクラスを付与する前に`if @travel_record.review? || is_error`で条件分岐しています。
※ この記述をしないと、未入力の場合でも緑枠が表示されてしまいます。

上記コードでは、`f.object.errors[:review].present?`でエラーの有無をチェックしています。エラーの場合は`form-control`と`is-invalid`を付与して**赤枠**を表示させ、入力があった場合は`form-control`と`is-valid`を付与して**緑枠**を表示させています。

##styleの修正
レビュー星を枠で囲って表示するため、styleの修正をしています。

```app/assets/stylesheets/aplication.scss
// エラーメッセージの設定
.form-control {
  height: auto;
}
```
`form-control`の`height`が悪さをしており、値を`auto`に変更した所、うまく表示することができました。


##エラーメッセージの表示
次に、**エラーメッセージ表示の実装**を行なっていきます。

```
div class=("invalid-feedback #{is_error ? 'd-block' : 'd-none'}")
 | オススメ度を入力してください
```

赤文字のエラー文を表示するには`invalid-feedback`クラスをもつ`<div>タグ`が必要になります。
こちらも三項演算子を使用し、エラーの場合は、`d-block`クラスを付与してエラーメッセージを**表示**させ、そうでない場合は、`d-none`を付与して**非表示**にしています。

2つのクラスはどちらもbootstrapが用意しているクラスです。

`d-block`・・・`display: block;`
`d-none`・・・`display: none;`



#最後に
以上がBootstrap4 バリデーションエラーの表示方法でした！
思った以上に時間が掛かってしまったのですが、正常に動作した時の喜びは、その疲れを吹き飛ばしますね笑
これからも色んなことに挑戦し、学んだことを投稿していきたいと思います！！

間違っている箇所や分かりづらい箇所が多々あるかと思います。
その際は、気軽にコメントいただけれると幸いです。

最後までご覧いただき、ありがとうございました!

https://qiita.com/shiraishiwataru/items/bf39e1ab9e1e4d6d8679

https://www.e-pokke.com/blog/bootstrap4-invalid-feedback.html