Rails 3:「field-with-errors」ラッパーはページの外観を変更します。これを回避するには?


131

メールフィールド:

<label for="job_client_email">Email: </label> 
<input type="email" name="job[client_email]" id="job_client_email">

このようになります:

without_error

しかし、電子メールの検証が失敗すると、次のようになります。

<div class="field_with_errors">
  <label for="job_client_email">Email: </label>
</div> 
<div class="field_with_errors">
  <input type="email" value="wrong email" name="job[client_email]" id="job_client_email">
</div>

これは次のようになります:

with_error

この外観の変更を回避するにはどうすればよいですか?


こんにちは@ misha-moroshko ですここで説明するように、親レベルでエラークラスを追加してみます。byebugを使用してコードをレールが、私はすぐに失われたに私は、これらのフィールドが親を持っているか否かをチェックすることによって、セットアップに少しスマートな方法でこの動作を望んでいた。..ダイブしようとした...
SanjiBukai

回答:


235

オーバーライドする必要がありますActionView::Base.field_error_proc。現在、次のように定義されていますActionView::Base

 @@field_error_proc = Proc.new{ |html_tag, instance| 
   "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
 }

これを内部のアプリケーションのクラスに置くことでオーバーライドできますconfig/application.rb

config.action_view.field_error_proc = Proc.new { |html_tag, instance| 
  html_tag
}

この変更を有効にするには、railsサーバーを再起動します。


4
一つの小さな疑問:なぜ両方labelinput包まれていますか?Railsは何をラップするかをどのように決定しますか?
Misha Moroshko

4
これはおそらく、エラーのあるフィールドのラベルにもスタイルを設定できるようにするためです。:また、あなたはあなたのためのフォームを作っているリソースのどの属性に属するフィールドにそれを伝えるためにラップするかを知っているレール f.label :passwordf.password_field :password@resource.errors存在することになる[:password]エラーセット。
Mosselman 2012年

3
Twitterブートストラップを使用している場合、またはfield_error_procで実行できる別の例が必要な場合は、この素晴らしい要点を確認してください。gist.github.com
Ryan Sandridge

2
なぜhtml_tag.html_safeではなく "#{html_tag}"。html_safeを実行するのですか?
Anurag 2013

3
Anurag:html_tagがnilまたは文字列以外の場合、プレーンなhtml_tag.html_safeはエラーを発生させます。「#{html_tag}」に入れると、暗黙的にhtml_tag.to_sが呼び出されます。これにより、文字列が返され、html_safeに応答できるようになります
sockmonk

100

div要素がブロック要素であるため、表示されている視覚的な違いが発生しています。このスタイルをCSSファイルに追加して、インライン要素のように動作するようにします。

.field_with_errors { display: inline; }

2
これは、display:で使用されているプロパティ(およびその他のレイアウトスタイル)を無効にするため、よくてもハックhtml_tagです。
ライアン

1
私はそれをハックとは考えていません。displayこのCSSである追加される前にプロパティが使用されてblock望ましくない視覚的な差異の原因となっています。タグの他のレイアウトスタイルを無効にすることはありません。ただし、エラーでフィールドをラップするタグを変更または削除する場合は、Ryan Biggの回答が最適です。
dontangg

ただし、これを試しましたが、フィールドが<p>タグの内部にある場合、<p>内の<div>は何があっても行を分割するため、(少なくともFirefoxでは)機能しないようです。Biggsソリューションを使用して、<divを<spanに置き換えるだけでうまくいくようです。
jpw 2012

72

私は現在、初期化子に配置されたこのソリューションを使用しています:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  class_attr_index = html_tag.index 'class="'

  if class_attr_index
    html_tag.insert class_attr_index+7, 'error '
  else
    html_tag.insert html_tag.index('>'), ' class="error"'
  end
end

これにより、追加の要素を作成せずに、適切なタグにクラス名を追加するだけで済みます。


2
これは、控えめな方法でエラーフィールドを使用するのに最適です。
ライアン

1
Rails 4.0.3で動作します。
松倉有希14

1
私のために働いた。ただし、変更に気づくにはRailsサーバーを再起動する必要がありました:)
Jezen Thomas

1
このソリューションは気に入りましたが、内に他のタグがある場合は機能しませんlabel
Caio Tarifa 2016年

こんにちは@Phobetron、本当にこれは素晴らしいソリューションです。ここで説明するように、親レベルでそのクラスを追加する方法を検索します。Railsのコードを調べましたが、byebugを使用してレンダリングプロセスを追跡できなくなってしまいました。これは実際に可能ですか?
SanjiBukai 2017

20

追加コードはによって追加されていActionView::Base.field_error_procます。field_with_errorsフォームのスタイル設定に使用していない場合は、次のようにオーバーライドできますapplication.rb

config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag.html_safe }

または、UIに適したものに変更できます。

config.action_view.field_error_proc = Proc.new { |html_tag, instance| "<span class='field_with_errors'>#{html_tag}</span>".html_safe }

これは私にとってはうまく機能しています。Twitter Bootstrapで使用するための最もエレガントなソリューションのようです
Avishai

5

私はRails 5とMaterialize-Sassを使用していますが、下の画像のように、失敗したフィールドの検証を処理するためのRailsのデフォルトの動作でいくつかの問題が発生しています。これはdiv、検証が失敗した入力フィールドに追加された追加が原因でした。

ここに画像の説明を入力してください

@Phobetronの回答を処理し、Hugo Demiglioの回答も変更します。これらのコードブロックにいくつかの調整を加えたところ、以下の場合にうまく機能しました。

  • 両方の場合inputとはlabel、自分の持っているclass属性の任意の場所を
    • <input type="my-field" class="control">
    • <label class="active" for="...">My field</label>
  • inputまたはlabelタグにclass属性 がない場合
    • <input type="my-field">
    • <label for="...">My field</label>
  • labelタグ内に別のタグがある場合class attribute
    • <label for="..."><i class="icon-name"></i>My field</label>

これらのすべてのケースで、errorクラスは、存在するclass場合は属性の既存のクラスに追加され、ラベルまたは入力タグに存在しない場合は作成されます。

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
    class_attr_index = html_tag.index('class="')
    first_tag_end_index = html_tag.index('>')

    # Just to inspect variables in the console
    puts '😎 ' * 50
    pp(html_tag)
    pp(class_attr_index)
    pp(first_tag_end_index)

    if class_attr_index.nil? || class_attr_index > first_tag_end_index
        html_tag.insert(first_tag_end_index, ' class="error"')
    else
        html_tag.insert(class_attr_index + 7, 'error ')
    end

    # Just to see resulting tag in the console
    pp(html_tag)
end

私と同じ条件の人に役立つと思います。


4

@phobetronの回答に加えて、のようなclass属性を持つ他のタグがある場合は機能しません<label for="..."><i class="icon my-icon"></i>My field</label>

私は彼の解決策にいくつかの変更を加えました:

# config/initializers/field_with_error.rb

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  class_attr_index = html_tag.index('class="')
  first_tag_end_index = html_tag.index('>')

  if class_attr_index.nil? || first_tag_end_index > class_attr_index
    html_tag.insert(class_attr_index + 7, 'error ')
  else
    html_tag.insert(first_tag_end_index, ' class="error"')
  end
end

ただし、フィールドにクラス属性がない場合、これは機能しません
mizurnix

2

何らかの理由でまだRails 2に取り組んでいる場合(私と同じように)、SOの投稿をここで確認してください

イニシャライザを配置するスクリプトを提供します。


2

覚えておくべきことの1つは、(今日、これを使用して作業していることを発見した)ラベルまたは入力フィールドのいずれかをフロートすると(すべての入力フィールドを右にフロートしている)、ActionView ::をオーバーライドしてもcssが壊れることです。 Base.field_error_proc。

別の方法は、次のようにCSSの書式設定のレベルをさらに下げることです。

.field_with_errors label {
  padding: 2px;
  background-color: red;
}

.field_with_errors input[type="text"] {
  padding: 3px 2px;
  border: 2px solid red;
}

2

一部のオブジェクトでこの恐ろしいことを無効にするオプションを作成しました

# config/initializers/field_error_proc.rb

module ActiveModel::Conversion
  attr_accessor :skip_field_error_wrapper
end

ActionView::Base.field_error_proc = Proc.new {|html_tag, instance|
  if instance.object && instance.object.skip_field_error_wrapper
    html_tag.html_safe
  else
    "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
  end
}

したがって、次のように使用できます。

@user.skip_field_error_wrapper = true
form_for(@user) do |f|
  ...
end

1

これは、@ Phobetronの答えの上に構築した私のソリューションです。このコードをに配置application.rbする<p><span>、対応するform.error :p呼び出しによって生成されたタグとタグがfields_with_errorscssタグを受け取ります。残りはerrorCSSクラスを受け取ります。

config.action_view.field_error_proc = Proc.new { |html_tag, instance|
  class_attr_index = html_tag.index 'class="'

  if class_attr_index
    # target only p's and span's with class error already there
    error_class = if html_tag =~ /^<(p|span).*error/
      'field_with_errors '
    else
      'error '
    end

    html_tag.insert class_attr_index + 7, error_class
  else
    html_tag.insert html_tag.index('>'), ' class="error"'
  end
}

私はこの方法が、フォーム全体で応答をスタイルするために、これまでのすべての中で最も柔軟で邪魔にならないことを発見しました。


1

スタイリングの目的だけの場合は(を気にしないdivでください)、これをCSSに追加するだけです。

div.field_with_errors {
 display: inline;
}

div以下のように動作しますspanと(ので、それはあなたのデザインに干渉しないdivブロック要素である- display: block;-それが閉じた後、デフォルトでは、それは新しい行の原因となります。spanですinlineので、それはしません)。


1

特定の要素、たとえばチェックボックスのエラーをオフにしたいだけなら、これを行うことができます:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  doc = Nokogiri::HTML::Document.parse(html_tag)
  if doc.xpath("//*[@type='checkbox']").any?
    html_tag
  else
    "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
  end
end

0

スタイルに関する問題のみの場合は、「field_with_errors」を上書きできます。しかし、それがアプリケーションの他のフォームに影響を与える可能性があるため、「field_with_errors」クラスをそのフォームでのみ上書きすることをお勧めします。

'parent_class'がフォームのエラーフィールドの親クラス(フォームのクラスまたはエラーフィールドの親要素のいずれかのクラス)の1つであると考えると、

  .parent_class .field_with_errors {
    display: inline;
  }

それは問題を修正するだけでなく、私たちのアプリケーションの他のフォームにも影響を与えません。

または

アプリケーション全体で「field_with_errors」のスタイルをオーバーライドする必要がある場合、@ dontanggが言ったように、

.field_with_errors { display: inline; } 

修正を行います。それが役に立てば幸い :)


0

field_error_procアプリケーション全体を変更したくない場合は、jQueryのアンラップにより、特定の問題領域に対して、より的を絞ったソリューションを提供できます。

$('FORM .field_with_errors > INPUT[type="checkbox"]').unwrap();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.