Rails 3: "hatalı alan" sarmalayıcısı sayfanın görünümünü değiştirir. Bundan nasıl kaçınılır?


132

E-posta alanı:

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

buna benzer:

hatasız

Ancak, e-posta doğrulaması başarısız olursa, şu hale gelir:

<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>

şuna benzeyen:

with_error

Bu görünüm değişikliğinden nasıl kaçınabilirim?


Merhaba @ misha-moroshko, hata sınıfını burada açıklandığı gibi ebeveyn düzeyinde eklemeye çalışıyorum . Byebug kullanarak ray koduna dalmaya çalıştım ama hemen kayboldum .. Bu davranışı, bu alanda bir ebeveyni olup olmadığını kontrol ederek biraz akıllıca ayarlamak istedim ..
SanjiBukai

Yanıtlar:


235

Geçersiz kılmalısın ActionView::Base.field_error_proc. Şu anda içinde şu şekilde tanımlanmıştır ActionView::Base:

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

Bunu uygulamanızın sınıfına yerleştirerek geçersiz kılabilirsiniz config/application.rb:

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

Bu değişikliğin etkili olması için raylar sunucusunu yeniden başlatın.


4
Bir küçük soru: Neden hem labelve inputsarılır? Rails neyi saracağına nasıl karar verir?
Misha Moroshko

4
Bu muhtemelen bir alanın etiketini de hatalarla biçimlendirebilmeniz için yapılır. Ayrıca, raylar neyin sarılacağını bilir çünkü hangi alanların hangi kaynak özniteliğine ait olduğunu form için oluşturduğunuzu söylersiniz: f.label :passwordve f.password_field :passwordiçinde @resource.errorsbir [:password]hata kümesi olur.
Mosselman

3
Twitter önyüklemesi ile çalışıyorsanız veya field_error_proc'ta neler yapabileceğinize dair başka bir örnek istiyorsanız, bu harika özete bir göz atın
Ryan Sandridge

2
Neden html_tag.html_safe değil de "# {html_tag}". Html_safe yapılsın?
Anurag

3
Anurag: html_tag sıfır olursa veya dizeden başka bir şey olursa, düz bir html_tag.html_safe hata verir. Bunu "# {html_tag}" içine koymak örtük olarak html_tag.to_s'yi çağırır, umarız ki bu bir dize döndürecektir ve bu daha sonra html_safe'e yanıt verecektir
sockmonk

100

Gördüğünüz görsel fark, diveleman bir blok eleman olduğu için oluyor . Satır içi bir öğe gibi davranmasını sağlamak için bu stili CSS dosyanıza ekleyin:

.field_with_errors { display: inline; }

2
Ne olursa olsun olumsuzlar çünkü bu en iyi kesmek display:üzerinde kullanılan (ve diğer düzen stilleri) olan mülkiyet html_tag.
Ryan

1
Bunu bir hile olarak görmüyorum. displayBu CSS ilave edilmeden önce özellik kullanılan blockistenmediği görsel fark neden olmaktadır. Etiketteki diğer düzen stillerini ortadan kaldırmaz. Ancak, alanı hatalarla saran etiketi değiştirmek / kaldırmak istiyorsanız Ryan Bigg'in cevabı mükemmel.
dontangg

Bunu denedim, ancak, eğer alanlarınız <p> etiketlerinin içindeyse, bir <p> içindeki bir <div> ne olursa olsun satırları keseceği için çalışmıyor (en azından Firefox'ta değil). Biggs çözümünü kullanarak, sadece <div'i <span ile değiştirmek hile yapacak gibi görünüyor.
jpw

72

Şu anda bir başlatıcıya yerleştirilmiş bu çözümü kullanıyorum:

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

Bu, ek öğeler oluşturmadan uygun etikete yalnızca bir sınıf adı eklememe izin veriyor.


2
Bu, hata alanlarını göze çarpmayan bir şekilde kullanmak için harikadır.
Ryan

1
Rails 4.0.3 üzerinde çalışır.
Yuki Matsukura

1
Benim için çalıştı. Yine de değişiklikleri fark etmek için raylar sunucusunu yeniden başlatmak zorunda kaldım :)
Jezen Thomas

1
Bu çözümü sevdim, ancak içinde başka bir etiket varsa işe yaramayacak label.
Caio Tarifa

Merhaba @Phobetron, gerçekten bu güzel bir çözüm. Bu sınıfı burada açıklandığı gibi ebeveyn düzeyinde eklemenin bir yolunu arıyorum . Ray koduna daldım ama byebug ile render sürecini takip edemediğimde kendimi hemen kaybettim .. Bunun gerçekten mümkün olduğunu düşünüyor musunuz?
SanjiBukai

20

Ekstra kod ekleniyor ActionView::Base.field_error_proc. field_with_errorsFormunuzun stilini belirlemek için kullanmıyorsanız , onu şurada geçersiz kılabilirsiniz application.rb:

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

Alternatif olarak, kullanıcı arayüzünüze uyan bir şeye değiştirebilirsiniz:

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

Bu benim için iyi çalışıyor; Twitter Bootstrap ile kullanım için en zarif çözüm gibi görünüyor
Avishai

5

Rails 5 ve Materialize-Sass ile çalışıyorum ve başarısız alan doğrulamalarını aşağıdaki görüntüdeki gibi ele almak için Rails'in varsayılan davranışıyla ilgili bazı sorunlar alıyorum ve bunun nedeni, divdoğrulamanın başarısız olduğu giriş alanlarına eklenen fazlalıktı .

görüntü açıklamasını buraya girin

@Phobetron cevabıyla çalışmak ve Hugo Demiglio'nun cevabını değiştirmek. Bu kod bloklarında bazı ayarlamalar yaptım ve aşağıdaki durumlarda iyi çalışan bir şey elde ediyorum:

  • İkisi de varsa inputve her yerde labelkendi classnitelikleri varsa
    • <input type="my-field" class="control">
    • <label class="active" for="...">My field</label>
  • Eğer inputveya labeletiketleri yok classniteliği
    • <input type="my-field">
    • <label for="...">My field</label>
  • labeletiketin içinde başka bir etiket varsaclass attribute
    • <label for="..."><i class="icon-name"></i>My field</label>

Tüm bu durumlarda, errorsınıf, classvarsa öznitelikteki mevcut sınıflara eklenecek veya etiket veya giriş etiketlerinde yoksa oluşturulacaktır .

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

Umarım benim gibi aynı koşullara sahip biri için faydalı olur.


4

@ Phobetron cevabına ek olarak, sınıf özniteliğine sahip başka bir etiketiniz olduğunda çalışmayan <label for="..."><i class="icon my-icon"></i>My field</label>.

Çözümünde bazı değişiklikler yaptım:

# 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

Ancak alanınızda sınıf özelliği yoksa bu işe yaramayacaktır
mizurnix

2

Nedense hala Raylar 2 üzerinde çalışıyorsanız SO sonrası check out (benim gibi) burada .

Başlatıcılara koymak için bir betik sunar.


2

Akılda tutulması gereken bir şey (bugün bunun üzerinde çalışmayı keşfettiğim gibi), etiketi veya giriş alanlarını kaydırırsanız (tüm giriş alanlarını doğru yüzdürüyorum), ActionView'ü geçersiz kılsanız bile css kırılacaktır :: Base.field_error_proc.

Alternatif olarak, CSS formatlamasında aşağıdaki gibi bir seviye daha derine inmektir:

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

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

2

Bazı nesneler için bu korkunç şeyi devre dışı bırakmak için bir seçenek yaptım

# 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
}

Yani şu şekilde kullanabilirsin:

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

1

Bu, @ Phobetron'un cevabının üzerine inşa ettiğim çözüm. Bu kodu yerleştirdiğinizde application.rb, sizin <p>ve <span>ilgili form.error :pçağrıların oluşturduğu etiketler fields_with_errorscss etiketini alacaktır . Geri kalanı errorCSS sınıfını alacak .

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
}

Bu yolu, formlarımdaki yanıtı şekillendirmek için öncekilerin en esnek ve göze batmayan yolu buldum.


1

Yalnızca şekillendirme amaçlıysa (umursamıyorsanız div), bunu css'nize ekleyebilirsiniz:

div.field_with_errors {
 display: inline;
}

divBir gibi hareket edecek spanve sizin tasarım engel olmaz (çünkü divbir blok öğesidir - display: block;- varsayılan olarak kapandıktan sonra, yeni bir satır neden olacaktır; spanise inlineöyle değil, bu yüzden).


1

Yalnızca belirli öğeler için hataları kapatmak istiyorsanız, örneğin onay kutuları , bunu yapabilirsiniz:

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

Yalnızca biçimlendirme sorunlarıyla ilgiliyse, "field_with_errors" alanının üzerine yazabiliriz. Ancak bu, uygulamamızdaki diğer formları etkileyebileceğinden, yalnızca bu formdaki "field_with_errors" sınıfının üzerine yazmak daha iyidir.

"Parent_class" ın, formun hata alanı için üst sınıftan biri olduğu düşünülürse (formun sınıfı veya hata alanı için herhangi bir üst öğenin sınıfı), o zaman

  .parent_class .field_with_errors {
    display: inline;
  }

Sorunu çözeceği gibi başvurumuzdaki diğer formları da rahatsız etmeyecektir.

VEYA

Tüm uygulama için "field_with_errors" stilini geçersiz kılmamız gerekirse, @dontangg'ın dediği gibi,

.field_with_errors { display: inline; } 

düzeltmeyi yapacak. Umarım yardımcı olur :)


0

field_error_procUygulamanızın tamamı için değişiklik yapmak istemiyorsanız , jQuery'nin açma kapaması belirli sorun alanları için daha hedefli bir çözüm sağlayabilir, örn.

$('FORM .field_with_errors > INPUT[type="checkbox"]').unwrap();

0

Kolayca ekstra devre dışı bırakabilir <div class="field_with_errors">bunu istemiyorsanız tamamen div hiç belli biçim elemanları. Örneğin, <label>'ler için istemiyorsanız , özel bir FormBuilder kullanın .

Örneğin:

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

ve sonra ya eklemek , builder: MyFormBuilderiçin için form_with/ ' form_forgörünümünde, OR ekleyin default_form_builder MyFormBuilder(bunu küresel davranış istiyorsanız veya temel denetleyicisi) Denetleyiciniz için.

Benzer şekilde girdiler ve diğer form öğeleri için de yapabilirsiniz.

Bu cevap için Jack Casey'ye teşekkür edin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.