form_label_and_error ヘルパー : 小林研 Rails Tips (41)

はじめに

Rails Tips の 41 回目です。以前、indexshow におけるテーブルラベルを記述する labels ヘルパーを紹介しました。form の場合には form.label で自動的に翻訳文字列が描画されます。ただし、validation などに抵触した場合には、このラベル部分にエラーを表示したいことが多いです。この部分も毎回記述するのは面倒なので、ラベルとエラーを同時に表示するヘルパーである form_label_and_error ヘルパーを作成しています。

form_label_and_error の使い方

通常は、form、model、属性名を渡します。model にエラーがあった場合にはエラーも表示します。

form_label_and_error f, year, :year

正常時: "<div><label for=\"year_year\">西暦</label></div>"
エラー時: "<div><div class=\"field_with_errors\"><label for=\"year_year\">西暦</label></div><br></br><span class=\"error_message\">西暦を入力してください。</span></div>"

add_text を追加すると、追加テキストを記述します。

form_label_and_error f, year, :year, add_text: "空欄不可"

正常時: "<div><label for=\"year_year\">西暦</label><span>空欄不可</span></div>"

form_label_and_error のテスト

上記のパターンをテストしています。

    describe "form_label_and_error" do
      let(:year) { years(:y2019) }
      let(:lbl) { "<label for=\"year_year\">西暦</label>" }
      let(:err) { "<span class=\"error_message\">西暦を入力してください。</span>" }
      it "form_label_and_error で適切なラベルが設定できること" do
        form_with model: year do |f|
          expect(helper.form_label_and_error(f, year,  :year)).to(
            eq "<div>#{lbl}</div>")
          expect(helper.form_label_and_error(f, year, :year, add_text: "add_text")).to(
            eq "<div>#{lbl}<span>add_text</span></div>")
          year.year = nil
          year.save
          expect(helper.form_label_and_error(f, year,  :year)).to(
            eq "<div><div class=\"field_with_errors\">#{lbl}</div><br></br>#{err}</div>")
        end
      end

form_label_and_error の実装

form_label_and_error のラベルの翻訳は form.label とするだけです。エラーがあった場合には、自動的に field_with_errors class は自動設定されます。ただし、メッセージは自動的には表示されないので、エラーが存在した場合には追加で表示をするようにしています。

  # @param [form] form
  # @param [Object] model
  # @param [Symbol] symbol
  # @param [String, nil] add_text
  # @return [Temple::HTML::SafeString] form 用の label
  # @note form_label_and_error
  def form_label_and_error(form, model, symbol, add_text: nil)
    content_tag :div do
      concat form.label symbol
      if add_text
        concat content_tag(:span, add_text)
      end
      if (error_messages = model.errors.full_messages_for(symbol)).present?
        concat content_tag(:br)
        concat content_tag(:span, error_messages.join(", "), class: "error_message")
      end
    end
  end

おわりに

こちらもほぼ定型的な繰り返しになるので、このようなヘルパーで記述量が減るのは嬉しいと思います。これまでエラーメッセージの描画をサボっていたのですが、このヘルパーに書き換えるだけでエラー表示も可能になるので、少しずつ修正しているところです。