バリデーションの実行タイミングを指定するオプション 【on:】



# はじめに/エラー発生時の状況

Railsでカレンダーアプリ（旅のしおり）的なものを実装中です。
日付や詳細、メンバー(deviseのユーザー登録機能を利用)を指定し、
旅行ページを登録します。

旅行ページ(trips)の参加ユーザー(users)は、
下図のようにtrip_usersと言う中間テーブルで、多対多のアソシエーションを組んで紐付けています。

<img width="737" alt="スクリーンショット 2020-11-15 16 14 29" src="https://user-images.githubusercontent.com/70574115/99179119-ba8a4e00-275d-11eb-9757-0b35614486f2.png">

必須項目を埋めて登録すると
tripsテーブルには
<img width="493" alt="スクリーンショット 2020-11-15 16 19 20" src="https://user-images.githubusercontent.com/70574115/99179174-603dbd00-275e-11eb-9ea3-2944dc095107.png">

trip_usersテーブルには
<img width="152" alt="スクリーンショット 2020-11-15 16 21 03" src="https://user-images.githubusercontent.com/70574115/99179201-a09d3b00-275e-11eb-9ce5-aa5f9e9c4a5f.png">

という具合に保存されます。



しかし、実装を進めていると…何かの拍子に

<img width="368" alt="スクリーンショット 2020-11-15 16 03 24" src="https://user-images.githubusercontent.com/70574115/99179018-c295be00-275c-11eb-8ff7-23380f2bad17.png">


見たことのないエラーと共に、、旅行ページの登録が突然出来なくなりました。
※当方、エラー文を日本語化しています。
先ほどまでと同じようにメンバーを選択しているのに、**「参加メンバーは不正な値です」**とは何ぞや…
私は何をしてしまったのでしょうか…

##### 開発環境
Ruby 2.6.5
Rails 6.0.3.4
MySQL
Visual Studio Code
(GoogleChrome)

# 原因の考察・検証
`binding.pry`でcreate処理を確認しました。

```
[1] pry(#<TripsController>)> trip_params
=> <ActionController::Parameters {
(中略)

 "user_ids"=>["", "2", "3", "4", "5", "6", "1"]} permitted: true>
[2] pry(#<TripsController>)> @trip = Trip.new(trip_params)
(中略)

[3] pry(#<TripsController>)> @trip.valid?
=> false
[4] pry(#<TripsController>)> @trip.errors.full_messages
=> ["参加メンバーは不正な値です"]
```
参加ユーザーはparamsでは`user_ids`にidが格納されて送られます。
これに対して、「不正な値」と言われているようです。
さっきまでは全然不正じゃなかったのに、何が不正になったのでしょうか…


何かエラーの心あたりはないものかと、最近何をやったか、記憶をたどると…

>「そういえば、パスワードの英数混合バリデーション書いてなかったな〜」

と、急に思い出して書いた記述を発見しました。

```user.rb
class User < ApplicationRecord
 (中略)

  PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i.freeze # 英数混合の正規表現
  validates :password, format: { with: PASSWORD_REGEX, message: 'は英字と数字を両方含んでください' }
end
```

試しにコメントアウトしてみると…戻りました！
こちらが原因だった模様…

どうやら、ユーザー新規登録時のバスワードに設定した英数混合バリデーションが、アソシエーションしている他モデルの生成時にも発動してしまっていた？みたいです。
数字のみのデータである`user_ids`に対しても、「英数混合にしてください！」と弾いていたと考えられます。
そんな珍事件もあるの…

では、その**バリデーションをユーザー登録のみに適用**できないものか…
調べた結果…

[【公式】Railsドキュメント/validates](https://railsdoc.com/page/validates)

<img width="379" alt="スクリーンショット 2020-11-15 16 29 30" src="https://user-images.githubusercontent.com/70574115/99179334-e1498400-275f-11eb-8997-3dc03659b53c.png">

こちらが使えそうです！


# 結果
`:on`オプションでバリデーション実行のタイミングを指定することができます。
今回はユーザー登録時にのみパスワードのバリデーションを実行したいので、`on: :create`を記述します。

↓修正後のUserモデル

```user.rb
class User < ApplicationRecord
 (中略)

  PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i.freeze # 英数混合の正規表現
  validates :password, format: { with: PASSWORD_REGEX, message: 'は英字と数字を両方含んでください' }, on: :create
end
```

これでパスワードのバリデーションを残しつつ、
旅行ページの登録機能も今まで通りに戻りました！

# 終わりに/感想
原因となる記述を探すのに時間がかかりました。
エラー時に遡れるように、マメにコミットする重要性も学びました…

初学者で拙い記事ですが、少しでもお役に立てると嬉しく思います。
最後まで読んでいただき、誠にありがとうございました。



##### 参考記事
[【公式/Railsガイド】Active Record バリデーション](https://railsguides.jp/active_record_validations.html#on
)
[【公式】Railsドキュメント/validates](https://railsdoc.com/page/validates)
[【Qiita】状況によってsave時に実行するバリデーションを切り替える](https://qiita.com/kadoppe/items/061d137e6022fa099872)
[【Qiita】Rails ｜onオプションを使ってバリデーションのタイミングを指定](https://qiita.com/ddd555/items/ec58e686607620c9d883)