Rails ile tamamen özel doğrulama hata mesajı


260

Rails kullanarak "Şarkı alanı boş olamaz" gibi bir hata mesajı almaya çalışıyorum. Aşağıdakileri yapmak:

validates_presence_of :song_rep_xyz, :message => "can't be empty"

... yalnızca "Song Rep XYW boş olamaz" görüntüler, bu alanın başlığı kullanıcı dostu olmadığından iyi değildir. Alanın başlığını nasıl değiştirebilirim? Veritabanındaki alanın gerçek adını değiştirebilirim, ancak birden fazla "şarkı" alanım var ve belirli alan adlarına ihtiyacım var.

Rayların doğrulama sürecini kesmek istemiyorum ve bunu düzeltmenin bir yolu olması gerektiğini hissediyorum.

Yanıtlar:


432

Şimdi, insancıllaştırılmış adları ve özel hata iletilerini ayarlamanın kabul edilen yolu yerel ayarları kullanmaktır .

# config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"

Şimdi "e-posta" özelliği için insancıllaştırılmış ad ve iletişim durumu doğrulama iletisi değiştirildi.

Doğrulama mesajları belirli bir model + özelliği, modeli, niteliği veya global olarak ayarlanabilir.


19
Mongoid kullanıyorsanız, activerecord: yerine mongoid:
Intentss

88
@graywh: Yorumlarda yer almıyorsa, bir cevapla ilgili sorular nereye gönderilmelidir? İşte I18n kılavuzu: guides.rubyonrails.org/i18n.html
Tyler Rick

4
Bu arada: Rails 3.1.3'teki doğrulayıcınızın mesaj parametresi için bir sembol iletirseniz, size e-eri bulamadığı için aradığı kapsamı söyleyecektir, bu yüzden tam olarak ne koyacağınızı bilirsiniz. yerel ayarlar yml.
aceofspades

4
Peki, bu iyi ve hepsi, ama ne sütun adı safça (ne kadar insan tarafından okunabilir olursa olsun) tamamen f-up dilbilgisine (özellikle ingilizce olmayan dillerde) yol açacaksa ne olacak? Gerçekten kullanmam gerekiyor errors.add :base, msgmu? Hatanın hangi sütunla ilgili olduğunu bilmek istiyorum, böylece doğru form alanında görüntüleyebilirim.
panzi

6
@graywh Belki bir şey eksik, ama mesajdan önce her zaman sütun adının başına gelmiyor mu? Hatta İngilizce I örn olmasını istiyorum The password is wrong.veya The email address is not valid.yerine Password is wrong.ve Email is not valid..
13'te panzi

65

Modelinizde:

validates_presence_of :address1, message: 'Put some address please' 

Sizce

<% m.errors.each do |attr, msg|  %>
 <%= msg %>
<% end %>

Bunun yerine yaparsan

<%= attr %> <%= msg %>

öznitelik adıyla bu hata iletisini alıyorsunuz

address1 Put some address please

tek bir özellik için hata mesajı almak istiyorsanız

<%= @model.errors[:address1] %>

Bu kabul edilebilir bir çözüm değil. Diğer tüm öznitelikler (attr + msg) için varsayılan davranışı istersem ne olur?
Rômulo Ceccon

İşte bu 2 şeyle oynayabilir ve çalıştırabilirsiniz
Federico

Yml dosyalarınızda görünmesi için bir sembol kullanmanız gerekirvalidates_presence_of :address1, :message => :put_some_address_please
Federico

Alan adı dahil edildiğinden, bu kabul edilemez
fatuhoku

62

Bunu dene.

class User < ActiveRecord::Base
  validate do |user|
    user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
  end
end

Bunu burada buldum .

İşte bunu yapmanın başka bir yolu. Yapmanız gereken model sınıfında bir human_attribute_name yöntemi tanımlamaktır. Yöntem, sütun adını dize olarak geçirilir ve doğrulama iletilerinde kullanılacak dizeyi döndürür.

class User < ActiveRecord::Base

  HUMANIZED_ATTRIBUTES = {
    :email => "E-mail address"
  }

  def self.human_attribute_name(attr)
    HUMANIZED_ATTRIBUTES[attr.to_sym] || super
  end

end

Yukarıdaki kod buradan


Sorun benim alanım denir: kullanıcı dostu olmayan song_rep_xyz (iyi, karmaşık bir şey),
marcgg

16
Rails 3 için "def self.human_attribute_name (attr)", "def self.human_attribute_name (attr, options = {})" olarak değiştirilmelidir, aksi takdirde bir hata döndürür
spacemonkey

3
Bunun için teşekkürler. Rails 2 için çalışan bir şeye ihtiyacım vardı. (Evet, zavallı ben ... :)
Dan Barron

18

Evet, bunu eklenti olmadan yapmanın bir yolu var! Ancak, söz konusu eklentiyi kullanmak kadar temiz ve zarif değildir. İşte burada.

Rails 3 olduğunu varsayarsak (önceki sürümlerde farklı olup olmadığını bilmiyorum),

bunu modelinizde saklayın:

validates_presence_of :song_rep_xyz, :message => "can't be empty"

ve görünüşte, ayrılmak yerine

@instance.errors.full_messages

İskele jeneratörünü kullandığımız gibi,

@instance.errors.first[1]

Ve sadece modelde belirttiğiniz mesajı, özellik adı olmadan alırsınız.

Açıklama:

#returns an hash of messages, one element foreach field error, in this particular case would be just one element in the hash:
@instance.errors  # => {:song_rep_xyz=>"can't be empty"}

#this returns the first element of the hash as an array like [:key,"value"]
@instance.errors.first # => [:song_rep_xyz, "can't be empty"]

#by doing the following, you are telling ruby to take just the second element of that array, which is the message.
@instance.errors.first[1]

Şimdiye kadar sadece bir mesaj gösteriyoruz, her zaman ilk hata için. Tüm hataları görüntülemek istiyorsanız, karma içinde döngü yapabilir ve değerleri gösterebilirsiniz.

Umut etmek bu yardım etmek.


16

Rails3 Tamamen yerelleştirilmiş mesajlar içeren kod:

User.rb modelinde doğrulamayı tanımlayın

validates :email, :presence => true

Config / locales / en.yml içinde

en:  
  activerecord:
    models: 
      user: "Customer"
    attributes:
      user:
        email: "Email address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "cannot be empty"

15

Özel doğrulama yönteminde şunları kullanın:

errors.add(:base, "Custom error message")

çünkü add_to_base kullanımdan kaldırıldı.

errors.add_to_base("Custom error message")


13

İlgili kabul cevap ve listede aşağı başka bir yanıt :

Nanamkim'in custom-err-msg çatalının Rails 5 ve yerel ayar ile çalıştığını onaylıyorum .

Yerel ayar mesajını bir düzeltme işareti ile başlatmanız yeterlidir ve mesajda öznitelik adını görüntülememelidir.

Şu şekilde tanımlanan bir model:

class Item < ApplicationRecord
  validates :name, presence: true
end

aşağıdaki ile en.yml:

en:
  activerecord:
    errors:
      models:
        item:
          attributes:
            name:
              blank: "^You can't create an item without a name."

item.errors.full_messages gösterecek:

You can't create an item without a name

her zamanki yerine Name You can't create an item without a name


11

David Easley tarafından yazılmış custom_error_message gem (veya bir eklenti olarak ) yüklemenizi tavsiye ederim

Gibi şeyler yapmanızı sağlar:

validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"

Bu eklentiyi geçmişte büyük bir başarıyla kullandım, ancak düzenli olarak bakıldığı görülmüyor.
Jared Brown

1
raylar 3 için bir mücevher olarak diğer yükleyebilirsiniz. sadece gem "custom_error_message" Gemfile ekleyin - daha fazla bilgi için github bakın
Dorian

Tam olarak ihtiyacım olan şey
olleicua

3
@DickieBoy Nanamkim'in çatalının ( github.com/nanamkim/custom-err-msg ) Rails 5 ile çalıştığını onaylıyorum. Aslında kabul edilen cevapla iyi oynuyor. Bunu ayrı bir cevap olarak yazacağım.
Rystraum

@Rystraum Benim hayatım boyunca bunun etrafındaki kullanım alanını hatırlayamıyorum ama cevap için teşekkürler! Gelecek için hatırlayacağım.
DickieBoy

10

Bir çözüm, i18n varsayılan hata biçimini değiştirmek olabilir:

en:
  errors:
    format: "%{message}"

Varsayılan değer format: %{attribute} %{message}


7

İşte başka bir yol:

Bu şablonu kullanırsanız:

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>

Kendi özel mesajınızı şöyle yazabilirsiniz:

class Thing < ActiveRecord::Base

  validate :custom_validation_method_with_message

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:_, "My custom message")
    end
  end

Bu şekilde, alt çizgi nedeniyle, tam ileti "Özel iletim" olur, ancak başlangıçtaki fazladan boşluk fark edilmez. Başlangıçta bu fazladan alanı gerçekten istemiyorsanız, .lstripyöntemi ekleyin .

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message.lstrip %></li>
    <% end %>
  </ul>
<% end %>

String.lstrip yöntemi ': _' tarafından oluşturulan ekstra alandan kurtulacak ve diğer hata mesajlarını değiştirmeden bırakacaktır.

Daha da iyisi, anahtar olarak özel mesajınızın ilk kelimesini kullanın:

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:my, "custom message")
    end
  end

Artık mesajın tamamı fazladan boşluk bırakmadan "Özel mesajım" olacak.

Tam iletinin "URL boş olamaz" gibi büyük harfle yazılmış bir kelimeyle başlamasını istiyorsanız, bu yapılamaz. Bunun yerine anahtar olarak başka bir kelime eklemeyi deneyin:

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:the, "URL can't be blank")
    end
  end

Şimdi iletinin tamamı "URL boş olamaz" olacaktır


ooo, hatta errors.add(:_, 'foobar')mesaj olarak 'foobar' yapabilir ve alabilirsiniz
xxjjnn

6

Sadece normal şekilde yapın:

validates_presence_of :email, :message => "Email is required."

Ama bunun yerine böyle göster

<% if @user.errors.any? %>
  <% @user.errors.messages.each do |message| %>
    <div class="message"><%= message.last.last.html_safe %></div>
  <% end %>
<% end %>

İadeler

"Email is required."

Yerelleştirme yöntemi kesinlikle bunu yapmanın "uygun" yoludur, ancak küçük, küresel olmayan bir proje yapıyorsanız ve sadece hızlı gitmek istiyorsanız - bu dosya atlamaktan kesinlikle daha kolaydır.

Alan adını dize başlangıcı dışında bir yere koymak için yeteneği gibi:

validates_uniqueness_of :email, :message => "There is already an account with that email."

2

Hepsini güzel bir listede listelemek istiyorsanız, ancak insan dostu olmayan ad kullanmadan, bunu yapabilirsiniz ...

object.errors.each do |attr,message|
  puts "<li>"+message+"</li>"
end

1

Sizce

object.errors.each do |attr,msg|
  if msg.is_a? String
    if attr == :base
      content_tag :li, msg
    elsif msg[0] == "^"
      content_tag :li, msg[1..-1]
    else
      content_tag :li, "#{object.class.human_attribute_name(attr)} #{msg}"
    end
  end
end

Öznitelik adı olmadan hata iletisini geçersiz kılmak istediğinizde, iletiyi ^ şu şekilde ekleyin:

validates :last_name,
  uniqueness: {
    scope: [:first_name, :course_id, :user_id],
    case_sensitive: false,
    message: "^This student has already been registered."
  }

raylar 5.1 / yakut 2.4 ile çalışmıyor? bu kapsamda model adını almak
Ben

@Ben benim için Rails 5.1.2, Ruby 2.4.1p111 üzerinde çalışıyor. Kodunuzu paylaşabilir misiniz?
luckyruby

daha fazla bakmak zorunda kaldım sanırım, kodu ve onun cevabını orada kontrol edebilirsiniz stackoverflow.com/q/45128434/102133
Ben

0

Takip etmeyi denedim, benim için çalıştı :)

1 iş.rb

class Job < ApplicationRecord
    validates :description, presence: true
    validates :title, 
              :presence => true, 
              :length => { :minimum => 5, :message => "Must be at least 5 characters"}
end

2 jobs_controller.rb

def create
      @job = Job.create(job_params)
      if @job.valid?
        redirect_to jobs_path
      else
        render new_job_path
      end     
    end

3 _form.html.erb

<%= form_for @job do |f| %>
  <% if @job.errors.any? %>
    <h2>Errors</h2>
    <ul>
      <% @job.errors.full_messages.each do |message|%>
        <li><%= message %></li>
      <% end %>  
    </ul>
  <% end %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div>
    <%= f.label :description %>
    <%= f.text_area :description, size: '60x6' %>

  </div>
  <div>
    <%= f.submit %>
  </div>
<% end %> 

0

İşte hala ihtiyacınız olması durumunda sizin için yararlı olabilir benim kod: Modelim:

validates :director, acceptance: {message: "^Please confirm that you are a director of the company."}, on: :create, if: :is_director?

Sonra mesajları göstermek için bir yardımcı oluşturdum:

module ErrorHelper
  def error_messages!
    return "" unless error_messages?
    messages = resource.errors.full_messages.map { |msg|
       if msg.present? && !msg.index("^").nil?
         content_tag(:p, msg.slice((msg.index("^")+1)..-1))
       else
         content_tag(:p, msg)
       end
    }.join

    html = <<-HTML
      <div class="general-error alert show">
        #{messages}
      </div>
    HTML

    html.html_safe
  end

  def error_messages?
    !resource.errors.empty?
  end
end

0

Eşsiz bir yaklaşım kimsenin bahsetmediğini gördüm!

İstediğim tüm özelleştirmeleri alabilmemin tek yolu after_validation, hata mesajını değiştirmeme izin vermek için bir geri arama kullanmaktı .

  1. Doğrulama mesajının normal olarak oluşturulmasına izin verin, doğrulama yardımcısında iletmeyi denemenize gerek yoktur.

  2. after_validationgörünüme ulaşmadan önce arka uçta bu doğrulama iletisinin yerini alacak bir geri arama oluşturun .

  3. Gelen after_validationyöntemle sadece normal bir dize gibi doğrulama mesajı ile istediğiniz her şeyi yapabilir! Dinamik değerleri bile kullanabilir ve bunları doğrulama mesajına ekleyebilirsiniz.


#this could be any validation
validates_presence_of :song_rep_xyz, :message => "whatever you want - who cares - we will replace you later"

after_validation :replace_validation_message

def replace_validation_message
    custom_value = #any value you would like
    errors.messages[:name_of_the_attribute] = ["^This is the replacement message where 
    you can now add your own dynamic values!!! #{custom_value}"]
end

After_validation yöntemi yerleşik raylar doğrulama yardımcısından çok daha geniş bir kapsama sahip olacaktır, böylece object.file_name ile yapmaya çalıştığınız gibi doğruladığınız nesneye erişebileceksiniz. Bu, aramaya çalıştığınız doğrulama yardımcısında çalışmaz.

Not: Kullandığımız ^@Rystraum bu referans işaret olarak doğrulama başında özellik adının kurtulmak için mücevher


0

graywh yanıtı, alan adının gösterilmesinde farklı bir şekilde yerelleştirilmişse en iyisidir. Dinamik alan adı durumunda (görüntülenecek diğer alanlara dayanarak), böyle bir şey yapardım

<% object.errors.each do |attr, msg| %>
<li>
  <% case attr.to_sym %>
  <% when :song_rep_xyz %>
    <%= #display error how you want here %>
  <% else %>
    <%= object.errors.full_message(attr, msg) %>
  <% end %>
</li>
<% end %>

diğerlerinde full_message yöntemi, rayların full_messages yöntemi içinde kullandığı yöntemdir, bu nedenle diğer durumlar için normal Rails hatalarını verir (Rails 3.2 ve üstü)

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.