使用Rails完全自定义validation错误消息

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

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

…只显示“歌词XYW不能空”,这是不好的,因为该字段的标题不是用户友好的。 我怎样才能改变领域本身的标题? 我可以更改数据库中字段的实际名称,但是我有多个“歌曲”字段,我需要具有特定的字段名称。

我不想绕过铁轨的validation过程,我觉得应该有办法解决这个问题。

现在,可接受的设置人性化名称和自定义错误消息的方法是使用语言环境 。

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

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

可以为特定模型+属性,模型,属性或全局设置validation消息。

尝试这个。

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

我在这里find了 。

这是另一种方式来做到这一点。 你所做的是在模型类上定义一个human_attribute_name方法。 该方法将字段名称作为string传递,并返回用于validation消息的string。

 class User < ActiveRecord::Base HUMANIZED_ATTRIBUTES = { :email => "E-mail address" } def self.human_attribute_name(attr) HUMANIZED_ATTRIBUTES[attr.to_sym] || super end end 

上面的代码是从这里

在你的模型中:

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

是的,没有插件就有办法做到这一点! 但是我不像使用上面提到的插件那样干净优雅。 这里是。

假设它是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 telleing ruby to take just the second element of that array, wich is the message. @instance.errors.first[1] 

到目前为止,我们只是只显示一条消息,总是针对第一个错误。 如果你想显示所有的错误,你可以在哈希中循环显示值。

希望有所帮助。

Rails3完全本地化的消息代码:

在模型user.rb中定义validation

 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" 

我build议安装David Easley最初编写的custom_error_message gem (或作为一个插件 )

它可以让你做这样的东西:

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

在自定义validation方法中使用:

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

因为add_to_base已被弃用。

errors.add_to_base("Custom error message")

相关的接受答案和列表中的另一个答案 :

我确认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

正常的做法就是这样做:

 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." 

本地化方法绝对是这样做的“正确”方法,但是如果您正在做一个非全局项目,并希望快速进行 – 这肯定比文件跳转更容易。

我喜欢将字段名称放在除string开头以外的地方:

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

String.lstrip方法将摆脱由':_'创build的额外空间,并保持其他任何错误消息不变。

或者甚至更好,将自定义消息的第一个单词用作关键字:

  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不能为空”

一个解决scheme可能是更改国际化的默认错误格式:

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

这里是我的代码,可以帮助你,如果你仍然需要它:我的模型:

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

然后我创build了一个帮手来显示消息:

 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