1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-11-15

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

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

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

スクリーンショット 2020-11-15 16 14 29

必須項目を埋めて登録すると
tripsテーブルには
スクリーンショット 2020-11-15 16 19 20

trip_usersテーブルには
スクリーンショット 2020-11-15 16 21 03

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

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

スクリーンショット 2020-11-15 16 03 24

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

開発環境

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

スクリーンショット 2020-11-15 16 29 30

こちらが使えそうです!

結果

: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 バリデーション
【公式】Railsドキュメント/validates
【Qiita】状況によってsave時に実行するバリデーションを切り替える
【Qiita】Rails |onオプションを使ってバリデーションのタイミングを指定

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?