バリデーションのエラー表示をなるべく出さない

Railsでバリデーションエラーのメッセージ表示を作り込むには、コストがかかります。なるべくHTMLとJavaScriptでバリデーションをやってしまい、Railsのバリデーションエラーはめったに出さない、というスタイルを目指したい。

## バリデーションの種類とHTML

確認したブラウザーは、Chrome、Firefox、iPhoneのSafari （2019年11月時点のバージョン）、およびIE11です。

### presence

input, textarea, selectなどたいていの入力欄ではrequired属性を使って、空かどうかをチェックできます。

#### input type="text"

required属性で空文字列をチェックできますが、スペースだけの文字列はチェックされません。pattern属性に正規表現を追加して空白文字以外の文字が含まれるようにします。

```HTML
<input type="text" name="title" required pattern=".*[^\s]+.*">
```

pattern属性の正規表現は、文字列全体を表す（先頭と最後に自動的に^と$が付く）ようなので、`"[^\s]+"`ではなく`".*[^\s]+.*"`としています。ちなみに全角空白は`\s`に含まれます。


#### textarea

textareaにはrequired属性はありますがpattern属性がありません。スペースや改行だけの値をチェックするには、JavaScriptを使うしかありません。

```HTML
<textarea id="body" name="body" cols="80" rows="3" required></textarea>
```

```JavaScript
$('form').on('submit', function(evt) {
  if(!$('#body').val().match(/[^\s]+/)) {
    evt.preventDefault();
    alert('本文を入力してください。');
  }
});
```

#### select

オプションに`value=""`があるselectにはrequiredを指定します。

```HTML
<select name="lang" required>
  <option value="">■選んでください</option>
  <option value="1">日本語</option>
  <option value="2">英語</option>
</select>
```

#### input type="checkbox"

チェックボックスにもrequiredは付けられます。

```HTML
<input type="checkbox" name="agreed" value="1" required> 利用規約を承認
```

#### input type="radio"

デフォルトでチェックが入っていないラジオボタンでは、requiredを付けておくと、どれか選ぶよう促す表示が出ます。

```HTML
<input type="radio" name="lang" value="ja" required> 日本語
<input type="radio" name="lang" value="en" required> 英語
```

### length

文字列のサイズ制限は、maxlength属性、minlength属性で指定します。ただし、IE11はminlengthに対応していないので、pattern属性で「何文字以上」を指定しておきます。

```HTML
<input type="password" name="password" required
  minlength="6" maxlength="255" pattern=".{6,}">
```

### format

pattern属性で半角英数字のみ、ひらがなのみ、などを指定できます。以下に便利な記事があるので参照してください。

- [HTML5におけるinput要素のpattern、type属性のおさらい](https://qiita.com/ka215/items/795a179041c705bef03b)

メールアドレスについては、以前に記事を書きました。

- [input type="email" の値の書式](https://qiita.com/kazutosato/items/31e6471af56e79adfdf0)

日付時刻については、ブラウザーで`<input type="date">`、`<input type="datetime-local">`のサポートが進んでいないので、当面はpattern属性を使うか、datepickerのようなライブラリを使う必要があります。

### numericality

必ず数値になるところは、`<input type="number">`にします。min属性とmax属性を指定すれば、最小値と最大値になります。

```HTML
<input type="number" name="number" min="10" max="99" required>
```

デフォルトでは`step="1"`、つまり小数点以下が入力できない状態になり、Railsの`only_integer: true`を満たします。小数点以下を入力させたければ、`step="0.1"`のようにします。

### inclusion

ラジオボタンかselectを使いましょう。

### confirmation

「パスワードの確認」は、JavaScriptでやればいいんじゃないでしょうか。Railsでやるまでもないと思います。

```HTML
パスワード：<input type="password" id="password" name="password" required><br>
パスワードの確認：<input type="password" id="password-confirmation" required>
```

```JavaScript
$('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にいたずらをして送信するユーザーに親切なメッセージを見せる必要はないので。