環境
Rails 5.2
内容
validatesのチェックで引っかかった場合、どのような仕組みでエラーが表示されているのか、確認してみました。
userモデルには、nameとname_idの2つのカラムがあり、次のようにvalidatesチェックをかけています。
validates :name, presence: true
validates :name_id, presence: true, uniqueness: true
editで編集画面を表示して、nameを空白にし、name_idに重複したデータを入力して、更新ボタンを押します。すると、コントローラのupdateメソッドに入ります。validatesのチェックは、@user.updateが実行されるタイミングで行われます。validatesのチェックで引っかかった場合、@user.updateの戻り値がfalseで返ってくるため、if文のelseに入ります。flashには「更新が失敗しました。」と表示されますが、具体的に、どの項目がどのような理由で更されなかったのかといった情報までは、このメッセージだけでは分かりません。
def update
@user = User.find(params[:id])
if @user.update(user_params)
flash[:notice] = "更新しました。"
redirect_to master_user_url
else
flash[:notice] = "更新が失敗しました。"
render :edit
end
end
@userオブジェクトのerrorsに、エラーに関する詳細な情報がセットされます。次の変数を使って拾うことができます。full_messagesを使うと、エラーが複数ある場合、全てのエラーを配列で取得することができます。
@user.errors.full_messages => ["名前を入力してください", "ユーザーIDはすでに存在します"]
項目名だけを指定すると、次のような取得のされ方をします。
@user.errors.messages[:name] => ["を入力してください"]
@user.errors.messages[:name_id] => ["はすでに存在します"]
validatesチェックのエラーメッセージはデフォルトで英語になっています。日本語に変換するために、ja.ymlファイルを次のように作成します。未入力エラーの場合は、「blank⇒を入力してください」に、重複チェックの場合は、「taken⇒はすでに存在します」にそれぞれ変換されます。変換後、エラーメッセージはformatの形式で出力されます。
ja:
activerecord:
attributes:
master/user:
name: 名前
name_id: ユーザーID
errors:
format: "%{attribute}%{message}"
messages:
blank: を入力してください
taken: はすでに存在します
配列にセットされたエラーメッセージは、eachで1個づつ取り出して画面表示します。presentを付けることで、errorsにエラーメッセージが存在するときだけ、画面表示することができます。
- if full_messages user.errors.present?
ul#error_explanation
- user.errors.each do |msg|
li = msg