Rails完全自定义验证错误消息

使用Rails我试图得到一个错误消息,如“歌曲字段不能为空”保存。做以下事情:

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

... 只显示“Song Rep XYW不能为空”,这是不好的,因为字段的标题不是用户友好的。如何更改字段本身的标题?我可以更改数据库中字段的实际名称,但我有多个“song”字段,我确实需要特定的字段名称。

我不想破坏rails的验证过程,我觉得应该有办法解决这个问题。

251387 次浏览

试试这个。

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宝石(或作为插件)

它可以让你做以下事情:

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

现在,设置人性化名称和自定义错误消息的公认方法是使用地区

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

现在,“email”属性的人性化名称而且的存在验证消息已被更改。

可以为特定的模型+属性、模型、属性或全局设置验证消息。

是的,有一种方法可以在没有插件的情况下做到这一点! 但是它不像使用上面提到的插件那样干净和优雅。

假设它是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 Code与完全本地化的消息:

在模型用户中。Rb定义验证

validates :email, :presence => true

在config /地区/ 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] %>

在自定义验证方法中使用:

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

的字符串。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不能为空"

接受的答案另一个答案相关:

我正在确认Nanamkim的顾客-呃-味精叉子与Rails 5和区域设置一起工作。

您只需要用一个插入符号开始locale消息,它不应该在消息中显示属性名称。

模型定义为:

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

当你想重写错误消息而不带属性名时,只需在消息前面加上^ like:

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

我试着跟随,为我工作:)

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

一个解决方案可能是改变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?

然后我创建了一个helper来显示消息:

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回调来允许我操纵错误消息。

  1. 允许正常创建验证消息,您不需要尝试在验证助手中更改它。

  2. 创建一个after_validation回调,它将在后端到达视图之前替换该验证消息。

  3. 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引用这个宝石所指出的那样

如果在显示字段名时locale不同,那么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错误(rails 3.2及更高版本)