はじめに
アプリ制作課題に取り組むと同時に過去課題を参考にしているわーちゃんです。今回はユーザー登録でバリデーションエラーが発生した場合、そのエラーメッセージを画面に表示するようなファイル設定、コードの記載を行ったあと、ローカルで確認することもできますが、ターミナルで確認できるようになってこそ!!大切だとおもったので、改めて学習しなおしてみました。
前回に比べて、「じゃあこの場合はどうなるのか?」という考えもできるようになってきたのでアウトプットの為にもまとめてみます。
さっそく手順
-
rails console
を起動
docker compose exec web rails c
で Rails コンソールを開く -
モデルのインスタンスを作成
バリデーションエラーを確認するためには、モデルのインスタンスを作成し、そのインスタンスが無効な状態である必要があります。たとえば、User
モデルがあると仮定します。user = User.new
ここでは、
User
モデルの新しいインスタンスを作成します -
エラーメッセージの確認
-
errors
メソッド
errors
メソッドを使用して、モデルインスタンスのエラーを確認できます。エラーオブジェクトはActiveModel::Errors
インスタンスです。user.errors
これで、バリデーションエラーの詳細が表示されます。通常、エラーは属性ごとにグループ化されています。
-
full_messages
メソッド
full_messages
メソッドを使用して、エラーメッセージをユーザーフレンドリーな形式で取得できます。user.errors.full_messages
これで、全てのエラーメッセージが配列として表示されます。メッセージは属性名とエラーメッセージが組み合わさった形になります。
-
-
具体的なコード例
例えば、User
モデルがemail
属性に対してpresence
バリデーションを持っている場合、email
属性が空のときにエラーメッセージを確認する方法は次の通りです。# Userモデルのインスタンスを作成(属性を設定せず) user = User.new # バリデーションを実行 user.valid? # エラーオブジェクトを確認 user.errors # => #<ActiveModel::Errors:0x00007f9b7c39e5e0 ...> # エラーメッセージを全て確認 user.errors.full_messages # => ["Email can't be blank"]
エラーメッセージはどこに記述されているか
エラーメッセージは、Rails アプリケーションのモデル内で設定されているバリデーションに基づいています。具体的には、エラーメッセージはモデルファイル内に記述されています。以下のファイルや場所で設定されている可能性があります。
-
1: モデルファイル内のバリデーション
モデルファイル (app/models/user.rb など) 内で、バリデーションとそのエラーメッセージが定義されています。以下は例になります。class User < ApplicationRecord # バリデーション設定 validates :email, presence: true validates :name, presence: true validates :password, presence: true, length: { minimum: 6 } validates :password_confirmation, presence: true end
-
2:エラーメッセージのカスタマイズ
デフォルトのエラーメッセージは、バリデーションのオプションで指定できます。例えば、password に対する length バリデーションでカスタムメッセージを指定することができます。validates :password, length: { minimum: 6, message: "is too short (minimum is %{count} characters)" }
-
3: 国際化 (I18n) ファイル
エラーメッセージは、国際化 (I18n) ファイルでカスタマイズされることもあります。config/locales/ ディレクトリ内にある YAML ファイル(例えば、config/locales/en.yml)でエラーメッセージを設定できます。
en:
errors:
messages:
blank: "can't be blank"
too_short: "is too short (minimum is %{count} characters)"
この設定によって、エラーメッセージがカスタマイズされると、デフォルトのメッセージが上書きされます。
実際の例1(あらためて解説付き)
$ docker compose exec web rails c
Loading development environment (Rails 7.1.3.4)
irb(main):001> user = User.new
=>
#<User:0x00007fc3732abb18
...
irb(main):002> user.valid?
User Exists? (0.8ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT $1 [["LIMIT", 1]]
=> false
irb(main):003> user.errors.full_messages
=>
["Password is too short (minimum is 6 characters)",
"Password confirmation can't be blank",
"Name can't be blank",
"Email can't be blank"]
irb(main):004* user.errors.each do |error|
irb(main):005* puts error.full_message
irb(main):006> end
Password is too short (minimum is 6 characters)
Password confirmation can't be blank
Name can't be blank
Email can't be blank
=>
[#<ActiveModel::Error attribute=password, type=too_short, options={:if=>#<Proc:0x00007fc37525f950 /myapp/app/models/user.rb:10 (lambda)>, :count=>6}>,
#<ActiveModel::Error attribute=password_confirmation, type=blank, options={:if=>#<Proc:0x00007fc37525a770 /myapp/app/models/user.rb:12 (lambda)>}>,
#<ActiveModel::Error attribute=name, type=blank, options={}>,
#<ActiveModel::Error attribute=email, type=blank, options={}>]
irb(main):007> user.errors
=> #<ActiveModel::Errors [#<ActiveModel::Error attribute=password, type=too_short, options={:if=>#<Proc:0x00007fc37525f950 /myapp/app/models/user.rb:10 (lambda)>, :count=>6}>, #<ActiveModel::Error attribute=password_confirmation, type=blank, options={:if=>#<Proc:0x00007fc37525a770 /myapp/app/models/user.rb:12 (lambda)>}>, #<ActiveModel::Error attribute=name, type=blank, options={}>, #<ActiveModel::Error attribute=email, type=blank, options={}>]>
1. user = User.new
このコードは仮のユーザーオブジェクト(User
モデルのインスタンス)を作成しています。
-
何のファイルに基づいているか: この仮のユーザーオブジェクトは、
app/models/user.rb
に定義されたUser
モデルに基づいて作成されています。User.new
はUser
クラスの新しいインスタンスを作成し、まだ保存されていないユーザーオブジェクトを作ります。
2. user.valid?
このコードは、User
モデルに定義されているバリデーションが適用されるかどうかを確認するためのものです。
-
動作の流れ:
-
app/models/user.rb
で定義されたバリデーション(例: 必須フィールドや文字数制限など)が、この仮のユーザーオブジェクトに適用されます。 - バリデーションに失敗すると
false
を返し、成功するとtrue
を返します。
-
3. user.errors.full_messages
このコードは、バリデーションに失敗した場合に発生するエラーメッセージを表示するためのものです。
-
動作の流れ:
-
user.valid?
を実行した後、user.errors.full_messages
を使って、発生したすべてのエラーメッセージを配列形式で返します。 - これにより、どのフィールドでエラーが発生し、どのような問題があるかがわかります。
-
※user.errors.each do |error| ... end
と user.errors
の違い
-
user.errors.each do |error| ... end
:- エラーメッセージを1つずつ取り出して、何らかの処理(例えば
puts error.full_message
でメッセージを表示)を行うためのループです。このコードを実行すると、各エラーメッセージが順番にコンソールに出力されます。
- エラーメッセージを1つずつ取り出して、何らかの処理(例えば
-
user.errors
:-
これは、エラーの詳細を含む
ActiveModel::Errors
オブジェクトを返します。これには、どのフィールドにどのようなエラーが発生しているかが含まれています。 -
例として、
user.errors
の返り値は以下のようになります:#<ActiveModel::Errors [#<ActiveModel::Error attribute=password, type=too_short, options={:count=>6}>, #<ActiveModel::Error attribute=email, type=blank, options={}>]>
-
このオブジェクトには、エラーメッセージそのものだけでなく、どの属性にどのようなタイプのエラーが発生しているかという詳細も含まれています。
-
実際の例1のまとめ
-
user = User.new
:app/models/user.rb
に基づいて仮のユーザーオブジェクトを作成。 -
user.valid?
:user.rb
で定義されたバリデーションを確認。 -
user.errors.full_messages
: バリデーションエラーの内容を確認。 -
user.errors.each do |error| ... end
: エラーメッセージを順番に処理。 -
user.errors
: エラーの詳細情報を含むオブジェクトを確認。
実際の例2(例1との比較)
irb(main):003> user = User.new(name: 'Hoge')
=>
#<User:0x00007f0889854100
...
irb(main):004> user.save
TRANSACTION (0.4ms) BEGIN
User Exists? (1.6ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT $1 [["LIMIT", 1]]
TRANSACTION (0.5ms) ROLLBACK
=> false
irb(main):005> user.errors
=> #<ActiveModel::Errors [#<ActiveModel::Error attribute=password, type=too_short, options={:if=>#<Proc:0x00007f0889a25a10 /myapp/app/models/user.rb:10 (lambda)>, :count=>6}>, #<ActiveModel::Error attribute=password_confirmation, type=blank, options={:if=>#<Proc:0x00007f0889a24458 /myapp/app/models/user.rb:12 (lambda)>}>, #<ActiveModel::Error attribute=email, type=blank, options={}>]>
irb(main):006> user.errors.full_messages
=>
["Password is too short (minimum is 6 characters)",
"Password confirmation can't be blank",
"Email can't be blank"]
irb(main):007* user.errors.each do |error|
irb(main):008* puts error.full_message
irb(main):009> end
Password is too short (minimum is 6 characters)
Password confirmation can't be blank
Email can't be blank
=>
[#<ActiveModel::Error attribute=password, type=too_short, options={:if=>#<Proc:0x00007f0889a25a10 /myapp/app/models/user.rb:10 (lambda)>, :count=>6}>,
#<ActiveModel::Error attribute=password_confirmation, type=blank, options={:if=>#<Proc:0x00007f0889a24458 /myapp/app/models/user.rb:12 (lambda)>}>,
#<ActiveModel::Error attribute=email, type=blank, options={}>]
コードの違いと説明
1. user = User.new(name: 'Hoge')
-
意味: これは
User
クラスの新しいインスタンスを作成し、その際にname
という属性に'Hoge'
という値を与えています。このオブジェクトはまだデータベースには保存されていません。 -
違い: 先ほどのコードは何も属性を指定せずにユーザーオブジェクトを作成しましたが、このコードでは
name
が設定されています。
2. user.save
-
意味: このメソッドは、
user
オブジェクトをデータベースに保存しようとします。保存が成功すればtrue
を返し、失敗すればfalse
を返します。 -
違い: 先ほどのコードでは
save
を使用せず、user.valid?
でオブジェクトが有効かどうかをチェックしていました。save
はデータベースに保存するため、バリデーションが重要になります。
3. user.errors
-
意味: これは
user
オブジェクトに関連するバリデーションエラーを保持しているオブジェクトです。save
が失敗したとき、どの属性でエラーが発生したかを表示します。
4. user.errors.full_messages
-
意味: バリデーションに失敗した場合のエラーメッセージを配列形式で取得します。例えば、
["Name can't be blank", "Email can't be blank"]
のような形で表示されます。
5. user.errors.each do |error|
-
意味:
user.errors
を使って、個々のエラーメッセージをループで処理します。このコードでは、各エラーメッセージをputs
を使って出力しています。
コードの違い
先ほどのコードでは user.valid?
を使ってバリデーションを手動でチェックし、その後エラーメッセージを確認しました。一方で、こちらのコードでは save
を使ってデータベースへの保存を試み、それに失敗した場合にエラーメッセージを確認する流れになっています。
-
save
の意味:save
は、オブジェクトが有効であればデータベースに保存し、無効であれば保存せず、エラー情報を保持します。 -
順番の違い:
save
を使うことで、データベースへの保存が試みられるため、valid?
ではなくsave
の結果に応じてエラー情報が格納されます。
この違いにより、save
が成功するか失敗するかによって、エラーメッセージが異なる場合があります。
さいごに
rails consoleから返り値を確認することが無事できました。saveを使用する時と使用しないときとでは返ってくるこたえもかわり、凄いなぁとあらためて実感。
今回の記事が何か参考になれば幸いです。