🪬

Railsのバリデーションエラーで、「field_with_errors」によるレイアウト崩れを防ぐ

に公開

はじめに

自分が使用していたもののバージョンです。

  • Ruby ver 2.6.3
  • Rails ver 5.2.3
  • bootstrap ver 4.3.1

またバリデーション処理が途中の状態なので、色々気になる箇所があるかもしれませんが、流してください。

現象

Rails のフォームを作成してバリデーションエラーを表示させるときに、入力欄のレイアウトが崩れるという現象が発生しました。

レイアウトが崩れた画像

これは、Rails が自動的に field_with_errors クラスを持つ div タグで、label タグや input タグを囲むことによって発生したものでした。

Railsでは、エラーメッセージを含むフィールドは自動的にfield_with_errorsクラスを持つdivタグで囲まれます。これを利用して、エラーメッセージをもっと目立たせるようにcssルールを定義しても構いません。

Rails をはじめよう / 5.10 バリデーションの追加 - Rails ガイド より

解決方法

解決方法は、2 つあります。

1. 自動挿入されないようにする
2. 挿入されたクラスのスタイルを編集する

この 2 つのどちらを選ぶかは、エラーメッセージが出るだけで十分であるなら前者で、エラーを目立たせるようなスタイルを当てたければ後者がいいと思います。

自動挿入されないようにする

まず 1 つ目は、Railsが自動で挿入しないように、設定をファイルに記述すればOKです。

config/application.rb に以下を追加しましょう。

module SampleApp
  class Application < Rails::Application
          # 他省略..
    config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag }
  end
end

上記を追加したら、サーバーを再起動させて再度確認してみると、レイアウトが崩れずにエラーメッセージが出るようになりました。

レイアウトを修正した後のフォームの画像

しかし、これでは Rails が提供してくれている機能を自ら使えなくしてしまいます。

そこで、2 つ目のやり方です。

挿入されたクラスのスタイルを編集する

結論から言うと、追加されたクラスにCSSでスタイルを当てるだけです。

そもそもこの機能は、バリデーションでエラーとなった箇所にクラスを挿入し、そのクラスにエラーを目立たせるスタイルを当てるようにと Rails が用意してくれているものです。

まずはレイアウトの崩れを修正します。

スタイルを記述しているファイルに以下を追記してください。
なお今回は、SASS を使用した例で説明していきます。

.field_with_errors {
  display: contents;
  // もしくは diplay: inline;
}

自分が作成したフォームでは「diplay: contents;」でできましたが、レイアウトによっては、「diplay: inline;」で修正できるかもしれません。

検証ツールを開いて、試してみてください。

次に入力欄の枠が赤色になるようにスタイルを記述します。

Bootstrap3の場合

field_with_errors クラスに対して Bootstrap3 の .has-error を extend することで入力欄を赤枠で表示さることができます。

.field_with_errors {
  display: contents;
  @extend .has-error;
}

Bootstrap4の場合

Bootstrap4 の場合は、.has-error が無くなっているので extend できません。
代わりに input タグに対して .is-invalid を extend します。

.field_with_errors {
  display: contents;
  input {
    @extend .is-invalid;
  }
}

上記を追記したらブラウザで確認してみてください。

スタイルを当てて修正したフォームの画像

このようにレイアウトも修正され、バリデーションエラーが発生した入力欄の枠が赤くなったら成功です。

まとめ

Rails のバリデーション機能によって「field_with_errors」クラスの div タグが挿入されたので、その機能を止めるかレイアウトを修正することで解決できました。

同じ現象に立ち会った人の役に立てればいいなと思います。

参考記事

Discussion