Полностью настраиваемое сообщение об ошибке проверки с Rails
используя Rails я пытаюсь получить сообщение об ошибке, например "поле песни не может быть пустым" при сохранении. Делаем следующее:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
... отображается только "Song Rep XYW не может быть пустым", что нехорошо, потому что название поля не является удобным для пользователя. Как изменить название самого поля ? Я мог бы изменить фактическое имя поля в базе данных, но у меня есть несколько полей "песня", и мне нужно иметь конкретные имена полей.
Я не хочу рубить вокруг процесса проверки rails, и я чувствую, что должен быть способ исправить это.
15 ответов
теперь принятый способ установить гуманизированные имена и пользовательские сообщения об ошибках -используйте районов.
# config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"
теперь гуманизированное имя и сообщение проверки присутствия для атрибута "электронная почта" было изменено.
сообщения проверки могут быть установлены для определенной модели + атрибута, модели, атрибута или глобально.
в вашей модели:
validates_presence_of :address1, :message => "Put some address please" 
на ваш взгляд
<% m.errors.each do |attr,msg|  %>
 <%=msg%>
<% end %>
если вы делаете вместо
<%=attr %> <%=msg %>
вы получили это сообщение об ошибке с именем атрибута
address1 Put some address please
если вы хотите получить сообщение об ошибке для одного атрибута
<%= @model.errors[:address1] %>
попробуйте это.
class User < ActiveRecord::Base
  validate do |user|
    user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
  end
end
Я нашел это здесь.
вот еще один способ сделать это. Вы определяете метод human_attribute_name в классе model. Метод передает имя столбца в виде строки и возвращает строку для использования в сообщениях проверки.
class User < ActiveRecord::Base
  HUMANIZED_ATTRIBUTES = {
    :email => "E-mail address"
  }
  def self.human_attribute_name(attr)
    HUMANIZED_ATTRIBUTES[attr.to_sym] || super
  end
end
приведенный выше код из здесь
Да, есть способ сделать это без плагина! Но это не так чисто и элегантно, как использование упомянутого плагина. Вот оно.
предполагая, что это Rails 3 (я не знаю, отличается ли он в предыдущих версиях),
сохранить это в вашей модели:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
и в поле зрения, вместо того, чтобы оставить
@instance.errors.full_messages
как это было, когда мы используем генератор, говоря:
@instance.errors.first[1]
и вы получите только сообщение, указанное в модель, без имени атрибута.
объяснение:
#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]
пока мы просто показываем только одно сообщение, всегда для первой ошибки. Если вы хотите отобразить все ошибки, вы можете зациклить хэш и показать значения.
надеюсь, что помогла.
код Rails3 с полностью локализованными сообщениями:
в модели пользователя.rb определите проверку
validates :email, :presence => true
в config/locales / en.в формате YML
en:  
  activerecord:
    models: 
      user: "Customer"
    attributes:
      user:
        email: "Email address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "cannot be empty"
в пользовательском методе проверки используйте:
errors.add(:base, "Custom error message")
поскольку add_to_base устарела.
errors.add_to_base("Custom error message")
Я рекомендую установка custom_error_message gem (или плагин) первоначально написал Дэвид Исли
это позволяет делать такие вещи, как:
validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
относятся к принято отвечать и еще один ответ вниз по списку:
Я подтверждаю это вилка nanamkim на заказ-err-msg работает с Rails 5 и с настройкой локали.
вам просто нужно запустить сообщение локали с помощью курсора, и оно не должно отображать имя атрибута в сообщении.
модель определяется как:
class Item < ApplicationRecord
  validates :name, presence: true
end
со следующими en.yml:
en:
  activerecord:
    errors:
      models:
        item:
          attributes:
            name:
              blank: "^You can't create an item without a name."
item.errors.full_messages будет отображать:
You can't create an item without a name
вместо Name You can't create an item without a name
просто сделайте это обычным способом:
validates_presence_of :email, :message => "Email is required."
но вместо этого отобразите его так
<% if @user.errors.any? %>
  <% @user.errors.messages.each do |message| %>
    <div class="message"><%= message.last.last.html_safe %></div>
  <% end %>
<% end %>
возвращает
"Email is required."
метод локализации, безусловно, является" правильным " способом сделать это, но если вы делаете немного, неглобальный проект и хотите просто быстро продвигаться-это определенно проще, чем скачивать файлы.
мне нравится это за возможность поместить имя поля где-то, кроме начала строки:
validates_uniqueness_of :email, :message => "There is already an account with that email."
вот еще один способ:
если вы используете этот шаблон:
<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>
вы можете написать вам собственное сообщение, как это:
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
таким образом, из-за подчеркивания полное сообщение становится "моим пользовательским сообщением", но дополнительное пространство в начале незаметно. Если вы действительно не хотите, чтобы дополнительное пространство в начале просто добавьте .lstrip метод.
<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message.lstrip %></li>
    <% end %>
  </ul>
<% end %>
Строку.метод lstrip избавится от дополнительного пространства, созданного ': _ 'и оставит любые другие сообщения об ошибках без изменений.
или даже лучше, используйте первое слово вашего пользовательского сообщения в качестве ключа:
  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:my, "custom message")
    end
  end
теперь полное сообщение будет "мое пользовательское сообщение" без дополнительного места.
если вы хотите, чтобы полное сообщение начиналось со слова с заглавной буквы "URL не может быть пустым", это невозможно сделать. Вместо этого попробуйте добавить другое слово в качестве ключа:
  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:the, "URL can't be blank")
    end
  end
теперь полное сообщение будет "URL не может быть пустой"
одним из решений может быть изменение формата ошибки по умолчанию i18n:
en:
  errors:
    format: "%{message}"
по умолчанию format: %{attribute} %{message}
Если вы хотите перечислить их все в хорошем списке, но без использования грубого нечеловеческого дружественного имени, вы можете это сделать...
object.errors.each do |attr,message|
  puts "<li>"+message+"</li>"
end
на ваш взгляд
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
Если вы хотите переопределить сообщение об ошибке без имени атрибута, просто добавьте сообщение с ^ как так:
validates :last_name,
  uniqueness: {
    scope: [:first_name, :course_id, :user_id],
    case_sensitive: false,
    message: "^This student has already been registered."
  }
Я пробовал следовать, работал на меня:)
1 работа.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.Эрб
<%= 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 %> 
вот мой код, который может быть полезен для вас в случае, если вам все еще нужен: Моя модель:
validates :director, acceptance: {message: "^Please confirm that you are a director of the company."}, on: :create, if: :is_director?
затем я создал помощник для отображения сообщений:
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
