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

mar*_*cgg 255 ruby-on-rails

使用Rails我试图在保存时收到类似"歌曲字段不能为空"的错误消息.执行以下操作:

validates_presence_of :song_rep_xyz, :message => "can't be empty"
Run Code Online (Sandbox Code Playgroud)

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

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

gra*_*ywh 417

现在,设置人性化名称和自定义错误消息的可接受方法是使用区域设置.

# config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"
Run Code Online (Sandbox Code Playgroud)

现在,已经更改了"email"属性的人性化名称状态验证消息.

可以为特定模型+属性,模型,属性或全局设置验证消息.

  • @graywh:如果不在评论中,应该在哪里发布有关答案的问题?这是I18n指南:http://guides.rubyonrails.org/i18n.html (88认同)
  • 如果您使用的是mongoid,请将activerecord替换为:mongoid: (19认同)
  • @graywh也许我错过了什么,但它不总是在消息之前添加列名吗?即使是英文,我也想要"密码错误."或"电子邮件地址无效."而不是"密码错误."和"电子邮件无效." (6认同)
  • 顺便说一下:如果你在Rails 3.1.3中为你的验证器的消息参数传递一个符号,它会告诉你它找不到的范围,所以你确切地知道你要放入什么locales yml. (4认同)
  • 好吧,这一切都很好,但如果天真地预先填充列名称(无论它的可读性如何)会导致完全f-uped语法(特别是在非英语语言中)?我真的需要使用`errors.add:base,msg`吗?我想知道错误的哪一列,所以我可以在正确的表单字段中显示它. (4认同)
  • 按语言设置字段名称很好,但是如何按语言设置自定义错误消息? (2认同)
  • @panzi啊,那么你可能想看一下ActiveModel :: Errors#full_message的实现,参见Rails I18n指南的5.2.2节http://guides.rubyonrails.org/i18n.html#overview-of-other - 内置的方法 - 即,提供-国际化支持 (2认同)

Fed*_*ico 64

在你的模型中:

validates_presence_of :address1, message: 'Put some address please' 
Run Code Online (Sandbox Code Playgroud)

在你看来

<% m.errors.each do |attr, msg|  %>
 <%= msg %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

如果你做了

<%= attr %> <%= msg %>
Run Code Online (Sandbox Code Playgroud)

您收到带有属性名称的此错误消息

address1 Put some address please
Run Code Online (Sandbox Code Playgroud)

如果要获取单个属性的错误消息

<%= @model.errors[:address1] %>
Run Code Online (Sandbox Code Playgroud)

  • 这是不可接受的,因为字段名称被包含在内 (2认同)

Mau*_*lin 61

试试这个.

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

我在这里找到了这个.

这是另一种方法.您要做的是在模型类上定义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
Run Code Online (Sandbox Code Playgroud)

上面的代码来自这里

  • 对于Rails 3,"def self.human_attribute_name(attr)"需要更改为"def self.human_attribute_name(attr,options = {})",否则返回错误 (16认同)
  • 谢谢你.我需要一些适用于Rails 2的东西.(是的,可怜的我...... :) (3认同)

小智 18

是的,没有插件就有办法做到这一点!但它并不像使用上述插件那样干净优雅.这里是.

假设它是Rails 3(我不知道它在以前的版本中是否有所不同),

将其保留在您的模型中:

validates_presence_of :song_rep_xyz, :message => "can't be empty"
Run Code Online (Sandbox Code Playgroud)

在视图中,而不是离开

@instance.errors.full_messages
Run Code Online (Sandbox Code Playgroud)

就像我们使用脚手架发电机时一样,放:

@instance.errors.first[1]
Run Code Online (Sandbox Code Playgroud)

并且您将获得您在模型中指定的消息,而没有属性名称.

说明:

#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]
Run Code Online (Sandbox Code Playgroud)

到目前为止,我们只显示一条消息,始终为第一个错误.如果您想显示所有错误,可以在哈希中循环并显示值.

希望有所帮助.


小智 15

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

在模型user.rb中定义验证

validates :email, :presence => true
Run Code Online (Sandbox Code Playgroud)

在config/locales/en.yml中

en:  
  activerecord:
    models: 
      user: "Customer"
    attributes:
      user:
        email: "Email address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "cannot be empty"
Run Code Online (Sandbox Code Playgroud)


ami*_*ena 15

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

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

因为add_to_base已被弃用.

errors.add_to_base("Custom error message")


Rys*_*aum 12

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

我确认nanamkim的自定义err-msg的分支可以与Rails 5配合使用,并且可以使用语言环境设置.

您只需要使用插入符启动语言环境消息,它不应在消息中显示属性名称.

模型定义为:

class Item < ApplicationRecord
  validates :name, presence: true
end
Run Code Online (Sandbox Code Playgroud)

以下内容en.yml:

en:
  activerecord:
    errors:
      models:
        item:
          attributes:
            name:
              blank: "^You can't create an item without a name."
Run Code Online (Sandbox Code Playgroud)

item.errors.full_messages 将显示:

You can't create an item without a name
Run Code Online (Sandbox Code Playgroud)

而不是通常的 Name You can't create an item without a name


Rya*_*igg 11

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

它可以让你做的事情:

validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
Run Code Online (Sandbox Code Playgroud)

  • @DickieBoy我确认nanamkim的fork(https://github.com/nanamkim/custom-err-msg)可以与Rails 5一起使用.它实际上与接受的答案一致.我会把它写成一个单独的答案. (3认同)
  • 谢谢!没有插件,有没有办法做到这一点? (2认同)

cap*_*013 8

一种解决方案可能是更改i18n默认错误格式:

en:
  errors:
    format: "%{message}"
Run Code Online (Sandbox Code Playgroud)

默认是 format: %{attribute} %{message}


Cru*_*nez 7

这是另一种方式:

如果您使用此模板:

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>
Run Code Online (Sandbox Code Playgroud)

您可以编写自己的自定义消息,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

这样,由于下划线,完整的消息变为"我的自定义消息",但开头的额外空间是不明显的.如果你真的不想在开始时增加额外的空间,只需添加.lstrip方法即可.

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message.lstrip %></li>
    <% end %>
  </ul>
<% end %>
Run Code Online (Sandbox Code Playgroud)

String.lstrip方法将摆脱':_'创建的额外空间,并将保留其他任何错误消息.

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

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:my, "custom message")
    end
  end
Run Code Online (Sandbox Code Playgroud)

现在,完整的消息将是"我的自定义消息",没有额外的空间.

如果您希望完整的消息以大写字母开头,例如"URL不能为空",则无法完成.而是尝试添加一些其他单词作为键:

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:the, "URL can't be blank")
    end
  end
Run Code Online (Sandbox Code Playgroud)

现在完整的消息将是"URL不能为空"


bri*_*ran 6

按照正常的方式做到:

validates_presence_of :email, :message => "Email is required."
Run Code Online (Sandbox Code Playgroud)

但是显示它就像这样

<% if @user.errors.any? %>
  <% @user.errors.messages.each do |message| %>
    <div class="message"><%= message.last.last.html_safe %></div>
  <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

返回

"Email is required."
Run Code Online (Sandbox Code Playgroud)

本地化方法绝对是实现这一目标的"正确"方法,但如果您正在做一些非全局项目并希望快速进行 - 这肯定比文件跳转更容易.

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

validates_uniqueness_of :email, :message => "There is already an account with that email."
Run Code Online (Sandbox Code Playgroud)