Pole e-mail:
<label for="job_client_email">Email: </label>
<input type="email" name="job[client_email]" id="job_client_email">
wygląda tak:
Jeśli jednak weryfikacja adresu e-mail się nie powiedzie, stanie się:
<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>
który wygląda tak:
Jak mogę uniknąć tej zmiany wyglądu?
ruby-on-rails
ruby-on-rails-3
validation
field-with-errors
Misha Moroshko
źródło
źródło
Odpowiedzi:
Powinieneś zastąpić
ActionView::Base.field_error_proc
. Obecnie jest zdefiniowany jako następujący wActionView::Base
:@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
Możesz to zmienić, umieszczając to w klasie swojej aplikacji wewnątrz
config/application.rb
:config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag }
Zrestartuj serwer rails, aby zmiana odniosła skutek.
źródło
label
iinput
są opakowane? W jaki sposób Railsy decydują, co owinąć?f.label :password
if.password_field :password
w@resource.errors
nie byłby[:password]
zestaw błędów.Widoczna różnica wizualna ma miejsce, ponieważ
div
element jest elementem blokowym. Dodaj ten styl do pliku CSS, aby zachowywał się jak element wbudowany:.field_with_errors { display: inline; }
źródło
display:
używaną właściwość (i inne style układu) whtml_tag
.display
Właściwość jest stosowany przed tym CSS dodajeblock
który powoduje różnicę wizualny, który nie jest pożądany. Nie neguje żadnych innych stylów układu w tagu. Jednak odpowiedź Ryana Bigga jest idealna, jeśli chcesz zmienić / usunąć tag, który otacza pole z błędami.Obecnie korzystam z tego rozwiązania, umieszczonego w inicjatorze:
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
Dzięki temu mogę po prostu dodać nazwę klasy do odpowiedniego tagu, bez tworzenia dodatkowych elementów.
źródło
label
.Dodatkowy kod jest dodawany przez
ActionView::Base.field_error_proc
. Jeśli nie używaszfield_with_errors
stylu do swojego formularza, możesz to zmienić wapplication.rb
:config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag.html_safe }
Alternatywnie możesz zmienić to na coś, co pasuje do Twojego interfejsu użytkownika:
config.action_view.field_error_proc = Proc.new { |html_tag, instance| "<span class='field_with_errors'>#{html_tag}</span>".html_safe }
źródło
Pracuję z Railsami 5 i Materialise-Sass i dostaję pewne problemy z domyślnym zachowaniem Railsów, aby traktować nieudane walidacje pól, jak na obrazku poniżej, a było to z powodu dodatkowych
div
dodanych do pól wejściowych, w których walidacja się nie powiodła.Praca z odpowiedzią @Phobetron i modyfikacja odpowiedzi Hugo Demiglio. Dokonałem pewnych poprawek w tych blokach kodu i coś działa dobrze w następujących przypadkach:
input
ilabel
mająclass
gdziekolwiek swój własny atrybut<input type="my-field" class="control">
<label class="active" for="...">My field</label>
input
lublabel
nie mająclass
atrybutu<input type="my-field">
<label for="...">My field</label>
label
tag ma w środku inny tag z rozszerzeniemclass attribute
<label for="..."><i class="icon-name"></i>My field</label>
We wszystkich tych przypadkach
error
klasa zostanie dodana do istniejących klas wclass
atrybucie, jeśli istnieją, lub zostanie utworzona, jeśli nie ma jej w etykiecie lub znacznikach wejściowych .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
Mam nadzieję, że będzie to przydatne dla kogoś z takimi samymi schorzeniami jak ja.
źródło
Oprócz odpowiedzi @phobetron, która nie działa, gdy masz inny tag z atrybutem klasy, np
<label for="..."><i class="icon my-icon"></i>My field</label>
.Zrobiłem kilka zmian w jego rozwiązaniu:
# 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
źródło
Jeśli z jakiegoś powodu nadal pracujesz na Railsach 2 (tak jak ja), zajrzyj do wpisu SO tutaj .
Oferuje skrypt do umieszczania inicjatorów.
źródło
Jedną rzeczą, o której należy pamiętać (jak odkryłem, pracując nad tym dzisiaj), jest to, że jeśli zmienisz etykietę lub pola wejściowe (przestawiam wszystkie pola wejściowe w prawo), css zepsuje się, nawet jeśli zastąpisz ActionView :: Base.field_error_proc.
Alternatywą jest zejście o jeden poziom głębiej w formatowaniu CSS w następujący sposób:
.field_with_errors label { padding: 2px; background-color: red; } .field_with_errors input[type="text"] { padding: 3px 2px; border: 2px solid red; }
źródło
Zrobiłem opcję wyłączenia tej strasznej rzeczy dla niektórych obiektów
# 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 }
Więc możesz go użyć w ten sposób:
@user.skip_field_error_wrapper = true form_for(@user) do |f| ... end
źródło
To jest moje rozwiązanie bazujące na odpowiedzi @ Phobetron. Umieszczając ten kod w
application.rb
, tagi<p>
i<span>
wygenerowane przez odpowiednieform.error :p
wywołania otrzymająfields_with_errors
tag css. Reszta otrzymaerror
klasę CSS.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 }
W ten sposób znalazłem najbardziej elastyczny i dyskretny sposób ze wszystkich poprzednich, aby nadać styl odpowiedzi w moich formularzach.
źródło
Jeśli jest to tylko do celów stylizacji (nie przeszkadza ci
div
), możesz po prostu dodać to do swojego css:div.field_with_errors { display: inline; }
div
Będą zachowywać się jakspan
i nie będzie kolidować z projektu (ponieważdiv
jest elementem bloku -display: block;
- domyślnie, spowoduje to nową linię po to zamyka,span
jestinline
, więc nie robi).źródło
Jeśli chcesz tylko wyłączyć błędy dla niektórych elementów, np. Pól wyboru , możesz to zrobić:
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
źródło
Jeśli chodzi tylko o problemy ze stylem, możemy nadpisać „field_with_errors”. Ale ponieważ może to wpłynąć na inne formularze w naszej aplikacji, lepiej jest nadpisać klasę „field_with_errors” tylko w tej formie.
Biorąc pod uwagę, że „parent_class” jest jedną z klas nadrzędnych dla pola błędu formularza (albo klasa formularza, albo klasa dowolnego elementu nadrzędnego dla pola błędu), to
.parent_class .field_with_errors { display: inline; }
Naprawi to problem, a także nie zakłóci żadnych innych formularzy w naszej aplikacji.
LUB
Jeśli musimy zastąpić styl „field_with_errors” dla całej aplikacji, to jak powiedział @dontangg,
.field_with_errors { display: inline; }
załatwi sprawę. Mam nadzieję, że to pomoże :)
źródło
Jeśli nie chcesz zmieniać
field_error_proc
całej aplikacji, rozpakowanie jQuery może zapewnić bardziej ukierunkowane rozwiązanie dla określonych obszarów problemowych, np.$('FORM .field_with_errors > INPUT[type="checkbox"]').unwrap();
źródło
Można łatwo wyłączyć dodatkowy
<div class="field_with_errors">
div całkowicie, jeśli nie chcą go w ogóle dla poszczególnych elementów formularza. Np. Jeśli nie chcesz tego przez<label>
's, użyj niestandardowego FormBuilder .Na przykład:
class MyFormBuilder < ActionView::Helpers::FormBuilder # Strip the containing div for labels associated with invalid fields: def label(method, text = nil, options = {}, &block) super(method, text, options, &block).gsub(%r{<div.*?>|<\/div>}, '').html_safe end end
a następnie albo dodać
, builder: MyFormBuilder
doform_with
/form_for
z punktu widzenia, OR dodaćdefault_form_builder MyFormBuilder
do kontrolera lub sterownika bazowego (jeśli chcesz to globalne zachowanie).Możesz zrobić podobnie dla danych wejściowych i innych elementów formularza.
Podziękowania dla Jacka Caseya za tę odpowiedź.
źródło