Railsでバリデーションエラーのメッセージ表示を作り込むには、コストがかかります。なるべくHTMLとJavaScriptでバリデーションをやってしまい、Railsのバリデーションエラーはめったに出さない、というスタイルを目指したい。
バリデーションの種類とHTML
確認したブラウザーは、Chrome、Firefox、iPhoneのSafari (2019年11月時点のバージョン)、およびIE11です。
presence
input, textarea, selectなどたいていの入力欄ではrequired属性を使って、空かどうかをチェックできます。
input type="text"
required属性で空文字列をチェックできますが、スペースだけの文字列はチェックされません。pattern属性に正規表現を追加して空白文字以外の文字が含まれるようにします。
<input type="text" name="title" required pattern=".*[^\s]+.*">
pattern属性の正規表現は、文字列全体を表す(先頭と最後に自動的に^と$が付く)ようなので、"[^\s]+"
ではなく".*[^\s]+.*"
としています。ちなみに全角空白は\s
に含まれます。
textarea
textareaにはrequired属性はありますがpattern属性がありません。スペースや改行だけの値をチェックするには、JavaScriptを使うしかありません。
<textarea id="body" name="body" cols="80" rows="3" required></textarea>
$('form').on('submit', function(evt) {
if(!$('#body').val().match(/[^\s]+/)) {
evt.preventDefault();
alert('本文を入力してください。');
}
});
select
オプションにvalue=""
があるselectにはrequiredを指定します。
<select name="lang" required>
<option value="">■選んでください</option>
<option value="1">日本語</option>
<option value="2">英語</option>
</select>
input type="checkbox"
チェックボックスにもrequiredは付けられます。
<input type="checkbox" name="agreed" value="1" required> 利用規約を承認
input type="radio"
デフォルトでチェックが入っていないラジオボタンでは、requiredを付けておくと、どれか選ぶよう促す表示が出ます。
<input type="radio" name="lang" value="ja" required> 日本語
<input type="radio" name="lang" value="en" required> 英語
length
文字列のサイズ制限は、maxlength属性、minlength属性で指定します。ただし、IE11はminlengthに対応していないので、pattern属性で「何文字以上」を指定しておきます。
<input type="password" name="password" required
minlength="6" maxlength="255" pattern=".{6,}">
format
pattern属性で半角英数字のみ、ひらがなのみ、などを指定できます。以下に便利な記事があるので参照してください。
メールアドレスについては、以前に記事を書きました。
日付時刻については、ブラウザーで<input type="date">
、<input type="datetime-local">
のサポートが進んでいないので、当面はpattern属性を使うか、datepickerのようなライブラリを使う必要があります。
numericality
必ず数値になるところは、<input type="number">
にします。min属性とmax属性を指定すれば、最小値と最大値になります。
<input type="number" name="number" min="10" max="99" required>
デフォルトではstep="1"
、つまり小数点以下が入力できない状態になり、Railsのonly_integer: true
を満たします。小数点以下を入力させたければ、step="0.1"
のようにします。
inclusion
ラジオボタンかselectを使いましょう。
confirmation
「パスワードの確認」は、JavaScriptでやればいいんじゃないでしょうか。Railsでやるまでもないと思います。
パスワード:<input type="password" id="password" name="password" required><br>
パスワードの確認:<input type="password" id="password-confirmation" required>
$('form').on('submit', function(evt) {
if($('#password').val() !== $('#password-confirmation').val()) {
evt.preventDefault();
alert('パスワードとパスワードの確認が一致しません。');
}
});
この例では、確認のほうのinputからname属性を外して送信されないようにしています。
uniqueness
メールアドレスやアカウント名の重複チェックは、Rails側でやればよいです。JavaScriptとAjaxでUIを作り込んでもよい。ここは、むしろ手間をかけるべきでしょう。
Railsのエラー表示について
もちろんRails側でもちゃんとバリデーションは行います(上記confirmationは除く)。ただし、HTMLとJavaScriptでバリデーションがカバーできるなら、Railsのエラーは「保存に失敗しました」だけでもいいし、「400 Bad Request」でもいいかもしれません。HTMLにいたずらをして送信するユーザーに親切なメッセージを見せる必要はないので。