提问人:marcgg 提问时间:5/1/2009 最后编辑:marcgg 更新时间:7/8/2023 访问量:264040
使用 Rails 的完全自定义验证错误消息
Fully custom validation error message with Rails
问:
使用 Rails,我试图在保存时收到类似“歌曲字段不能为空”的错误消息。执行以下操作:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
...仅显示“Song Rep XYW can't be empty”,这并不好,因为字段的标题对用户不友好。如何更改字段本身的标题?我可以更改数据库中字段的实际名称,但我有多个“歌曲”字段,并且我确实需要有特定的字段名称。
我不想绕过 rails 的验证过程,我觉得应该有一种方法来解决这个问题。
答:
试试这个。
class User < ActiveRecord::Base
validate do |user|
user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
end
end
我在这里找到了这个。
Rails 3 到 6 的更新:
validate do |user|
user.errors.add(:base, "Country can't be blank") if user.country_iso.blank?
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
上面的代码来自这里
评论
我建议安装最初由 David Easley 编写的 custom_error_message gem(或作为插件)
它可以让你做一些事情,比如:
validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
评论
gem "custom_error_message"
现在,设置人性化名称和自定义错误消息的公认方法是使用区域设置。
# config/locales/en.yml
en:
activerecord:
attributes:
user:
email: "E-mail address"
errors:
models:
user:
attributes:
email:
blank: "is required"
现在,“email”属性的人性化名称和状态验证消息已更改。
可以为特定模型+属性、模型、属性或全局设置验证消息。
评论
errors.add :base, msg
The password is wrong.
The email address is not valid.
Password is wrong.
Email is not valid.
是的,有一种方法可以在没有插件的情况下做到这一点! 但它不如使用上述插件干净优雅。在这里。
假设是 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]
到目前为止,我们只显示一条消息,总是针对第一个错误。如果要显示所有错误,可以在哈希中循环并显示值。
希望能有所帮助。
评论
如果你想把它们都列在一个不错的列表中,但又不使用粗糙的非人类友好名称,你可以这样做......
object.errors.each do |attr,message|
puts "<li>"+message+"</li>"
end
带有完全本地化消息的 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"
只需以正常方式进行操作:
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."
在模型中:
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] %>
评论
validates_presence_of :address1, :message => :put_some_address_please
在自定义验证方法中,使用:
errors.add(:base, "Custom error message")
因为add_to_base已被弃用。
errors.add_to_base("Custom error message")
这是另一种方法:
如果使用此模板:
<% 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不能为空”
评论
errors.add(:_, 'foobar')
我正在确认 nanamkim 的 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
在您的视野中
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.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 %>
一种解决方案可能是更改 i18n 默认错误格式:
en:
errors:
format: "%{message}"
默认值为format: %{attribute} %{message}
这是我的代码,如果您仍然需要它,它对您有用: 我的模型:
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
评论
一种我从未见过任何人提及的独特方法!
我能够获得我想要的所有自定义的唯一方法是使用回调来允许作错误消息。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方法将比内置的 rails 验证助手具有更大的范围,因此您将能够访问您正在验证的对象,就像您尝试使用 object.file_name 一样。这在您尝试调用它的验证帮助程序中不起作用。
注意:我们使用 来删除验证开始时的属性名称,正如@Rystraum指出的那样引用此 gem^
如果 Graywh 在显示字段名称时实际上存在不同的区域设置,那么它的答案是最好的。对于动态字段名称(基于要显示的其他字段),我会执行类似操作
<% 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 %>
else 上的 full_message 方法是 Rails 在 full_messages 方法中使用的方法,因此在其他情况下(Rails 3.2 及更高版本)会给出正常的 Rails 错误
升级了@Federico的答案,适用于所有字段错误。
在您的 :controller.rb
flash[:alert] = @model.errors.messages.values
# [["field1_err1", "field1_err2"], ["field2_err1"], ["field3_err1"]]
messages
方法“返回属性的哈希值及其错误消息数组”,如 rails 文档中所示。
然后,要在表单中显示这些错误,请执行以下操作:
<% flash.each do |type, type_arr| %>
<% type_arr.each do |msg| %>
<ul>
<li>
<%= msg.to_sentence %>
</li>
</ul>
<% end %>
<% end %>
评论