Rails 3: оболочка "field-with-errors" меняет внешний вид страницы. Как этого избежать? - PullRequest
129 голосов
/ 11 марта 2011

Адрес электронной почты:

<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

Как можно избежать этого изменения внешности?

Ответы [ 12 ]

229 голосов
/ 11 марта 2011

Вы должны переопределить 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, чтобы изменения вступили в силу.

99 голосов
/ 11 марта 2011

Визуальное различие, которое вы видите, происходит потому, что элемент div является блочным элементом. Добавьте этот стиль в свой CSS-файл, чтобы он вел себя как встроенный элемент:

.field_with_errors { display: inline; }
70 голосов
/ 05 декабря 2011

Я в настоящее время использую это решение, помещенное в инициализатор:

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

Это позволяет мне просто добавить имя класса к соответствующему тегу без создания дополнительных элементов.

20 голосов
/ 11 марта 2011

Дополнительный код добавляется 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 }

В качестве альтернативы, вы можете изменить ее на что-то, подходящее вашему интерфейсу:

config.action_view.field_error_proc = Proc.new { |html_tag, instance| "<span class='field_with_errors'>#{html_tag}</span>".html_safe }
4 голосов
/ 30 января 2017

Я работаю с Rails 5 и Materialize-Sass , и у меня возникают некоторые проблемы с поведением по умолчанию из Rails для обработки неудачных проверок полей, как на рисунке ниже, и это было из-за дополнительных div добавлено в поля ввода, где проверка не удалась.

enter image description here

Работа с ответом @Phobetron и изменение ответа Уго Демильо тоже. Я внес некоторые коррективы в эти блоки кода, и что-то работает хорошо в следующих случаях:

  • Если у 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 голосов
/ 28 марта 2016

Кроме ответа @phobetron, который не работает, когда у вас есть другой тег с атрибутом класса, например <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
2 голосов
/ 15 января 2015

Я сделал возможность отключить эту ужасную вещь для некоторых объектов

# 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
2 голосов
/ 06 июня 2012

Одна вещь, которую нужно иметь в виду (как я обнаружил, работая с этим сегодня), это то, что если вы плаваете либо надписью, либо над полями ввода (я переворачиваю все поля ввода правильно), css прервется, даже если вы переопределитеActionView :: 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 голосов
/ 31 мая 2012

Если по какой-то причине вы все еще работаете над Rails 2 (как я), посмотрите SO SO здесь .

Он предлагает скрипт для установки в инициализаторы.

1 голос
/ 28 марта 2014

Если это просто для стилизации (вы не против div), вы можете просто добавить это к своему CSS:

div.field_with_errors {
 display: inline;
}

div будет действовать как spanи это не будет мешать вашему дизайну (так как div является элементом блока - display: block; - по умолчанию, это вызовет новую строку после закрытия; span равно inline, так что это не так).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...