RailsのActiveRecordを使っていてバリデーションエラーが発生した場合に、Modelの errors に各種エラーメッセージが格納されます。
errorsを回してエラーを表示するだけであれば簡単ですが、下図のように入力フォームのそばにエラーメッセージを表示しようとすると少し面倒です。
このような入力フォームとエラーメッセージにするためには、テンプレートに以下の処理を追加しなければなりません。
- フォームの枠の色を変えるための条件分岐
- エラーメッセージを表示するための条件分岐とHTMLのタグ
パラメータが1つだけであればそんなに手間ではありませんが、複数ある場合はすべてのフォームに1と2を追加していかなければなりません。
対応方針
1と2を追加する手間を省くために、入力フォーム作成時に自動的に関連するエラーメッセージも作成されるフォームビルダーを実装します。
「エラーメッセージがあるときに〜」の条件分岐の記述がすべてフォームビルダークラスに移るため、テンプレートがスッキリします。
事前知識
独自のフォームビルダーは、以下のようにFormBuilderクラスを継承することで定義できます。
class FormWithErrorMessageBuilder < ActionView::Helpers::FormBuilder # 独自の処理を記述 end
また、処理の過程でHTMLタグを生成したい場合には、content_tag
などの専用メソッドを用います。div
ブロックを新たに作成したい場合は、以下のように記述します。第三引数のオプションには、id や class などのHTMLの属性を指定できます。
# 第一引数にセレクター、第二引数に内容、第三引数以降にオプション @template.content_tag(:div, "エラーメッセージ", class: "error-class") # ブロック形式の記述も可能、タグが入れ子になる場合はこちらで @template.content_tag(:div, class: "error-class") do エラーメッセージ end
今回は、エラーがある場合のみエラーメッセージを表示したいです。なのでエラーがある場合には、上記のcontent_tagを使ってエラーメッセージのHTMLタグを動的に追加します。
実装
最終的に以下のような独自のフォームビルダーを実装しました。error-class
の部分には、エラー発生時のcssクラスを自由に設定してください。
# form_helper.rb module FormHelper class FormWithErrorMessageBuilder < ActionView::Helpers::FormBuilder # 従来のフォームに加えて、エラーがある場合にエラーメッセージを表示するメソッド def input_field_with_error(attribute, options={}, &block) # 入力フォームと同じ属性のエラーメッセージを取得する error_messages = @object.errors.full_messages_for(attribute) # エラーがある場合のみ、エラー用のHTMLにする if error_messages.any? options[:class] << "error-class" error_contents = create_error_div(attribute, error_messages) end # 従来の入力フォーム と 生成されたエラーメッセージ を連結して返す block.call + error_contents || "" end # エラーメッセージのHTMLタグを作成する def create_error_div(attribute, messages) # content_tag でHTMLタグを生成 @template.content_tag(:div, class: "error-class") do messages.each do |message| @template.concat(@template.content_tag(:div, message)) end end end # 既存のビューヘルパーメソッドをオーバーライドする def text_field(attribute, options={}) input_field_with_error(attribute, options) do super end end end end
オーバーライドしたビューヘルパーの使用時に属性名が input_field_with_error
に受け渡され、入力フォームとエラーメッセージが対応づけられます。見かけ上はRails標準のビューヘルパーを使っているだけですが、 input_field_with_error
がかまされているのでエラーがある場合には関連するエラーメッセージが表示されます。
この例では、text_field
のみエラーメッセージが表示されるようになっています。それ以外の入力フォームにもエラーメッセージを表示したい場合は、同様に既存のビューヘルパーメソッドをオーバーライドすればよいです。
email_field
, password_field
にもエラーメッセージが表示されるようにしましょう。 input_field_with_error
をかますだけなので簡単にできます。
def email_field(attribute, options={}) input_field_with_error(attribute, options) do super end end def password_field(attribute, options={}) input_field_with_error(attribute, options) do super end end
独自のフォームビルダーを使うように設定する
フォーム作成時のビューヘルパーの引数に :builder => FormHelper::FormWithErrorMessageBuilder
を指定するなどして、独自のフォームビルダを使うための設定をお忘れなく。