Полностью настраиваемое сообщение об ошибке проверки с Rails
Использование Rails Я пытаюсь получить сообщение об ошибке, например "Поле песни не может быть пустым" при сохранении. Выполнение следующих действий:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
... отображает только "Song Rep XYW не может быть пустым", что не очень хорошо, потому что заголовок поля не является удобным для пользователя. Как я могу изменить название самого поля? Я могу изменить фактическое имя поля в базе данных, но у меня есть несколько полей "песни", и мне нужно иметь конкретные имена полей.
Я не хочу взломать процесс проверки рельсов, и я чувствую, что должен быть способ исправить это.
Ответы
Ответ 1
Теперь принятый способ установить гуманизированные имена и настраиваемые сообщения об ошибках - использовать локали.
# config/locales/en.yml
en:
activerecord:
attributes:
user:
email: "E-mail address"
errors:
models:
user:
attributes:
email:
blank: "is required"
Теперь очеловеченное имя и сообщение о подтверждении присутствия для атрибута "email" были изменены.
Сообщения проверки могут быть установлены для конкретной модели + атрибута, модели, атрибута или глобально.
Ответ 2
В вашей модели:
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] %>
Ответ 3
Попробуйте это.
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 в классе модели. Метод передается имя столбца в виде строки и возвращает строку для использования в сообщениях проверки.
class User < ActiveRecord::Base
HUMANIZED_ATTRIBUTES = {
:email => "E-mail address"
}
def self.human_attribute_name(attr)
HUMANIZED_ATTRIBUTES[attr.to_sym] || super
end
end
Вышеприведенный код из здесь
Ответ 4
Да, есть способ сделать это без плагина! Но это не так чисто и элегантно, как использование упомянутого плагина. Вот.
Предполагая, что это 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]
Пока что мы показываем только одно сообщение, всегда для первой ошибки. Если вы хотите отобразить все ошибки, вы можете зациклить в хэш и показать значения.
Надеюсь, что это помогло.
Ответ 5
Код Rails3 с полностью локализованными сообщениями:
В модели user.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"
Ответ 6
В пользовательском методе проверки используйте:
errors.add(:base, "Custom error message")
поскольку add_to_base устарела.
errors.add_to_base("Custom error message")
Ответ 7
Я рекомендую установить гем custom_error_message (или как плагин), изначально написанный Дэвидом Исли
Это позволяет вам делать такие вещи, как:
validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
Ответ 8
В связи с принятым ответом и еще один ответ в списке:
Я подтверждаю, что nanamkim fork custom-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
Ответ 9
Вот еще один способ:
Если вы используете этот шаблон:
<% 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 %>
Метод String.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 не может быть пустым"
Ответ 10
Одним из решений может быть изменение формата ошибки по умолчанию i18n:
en:
errors:
format: "%{message}"
Значение по умолчанию format: %{attribute} %{message}
Ответ 11
Просто делайте это обычным способом:
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."
Ответ 12
Если вы хотите перечислить их все в хорошем списке, но без использования грубого дружественного имени, вы можете сделать это...
object.errors.each do |attr,message|
puts "<li>"+message+"</li>"
end
Ответ 13
На ваш взгляд
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."
}
Ответ 14
Я пробовал следовать, работал у меня:)
1 job.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 %>
Ответ 15
Вот мой код, который может быть вам полезен, если он вам еще нужен:
Моя модель:
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
Ответ 16
Если вы работаете с Rails-5, вы также можете перейти к следующему:
validates: user_name, наличие: true, уникальность: {сообщение: "Имя пользователя уже существует."}
Ответ 17
Уникальный подход, который я не видел ни у кого!
Единственный способ получить все настройки, которые я хотел, это использовать after_validation
вызов after_validation
чтобы я мог манипулировать сообщением об ошибке.
-
Разрешите создание сообщения проверки как обычно, вам не нужно пытаться изменить его в помощнике проверки.
-
создайте after_validation
вызов after_validation
, который заменит это сообщение проверки в серверной части до того, как оно попадет в представление.
-
В методе after_validation
вы можете делать все что угодно с сообщением проверки, как обычная строка! Вы даже можете использовать динамические значения и вставить их в сообщение проверки.
#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 будет иметь гораздо большую область действия, чем встроенный помощник проверки рельсов, поэтому вы сможете получить доступ к объекту, который вы проверяете, так же, как вы пытаетесь это сделать с object.file_name. Что не работает в помощнике проверки, где вы пытаетесь вызвать его.
Примечание: мы используем ^
чтобы избавиться от имени атрибута в начале проверки, так как @Rystraum указал на ссылку на этот гем