首页 文章

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

提问于
浏览
242

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

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

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

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

17 回答

  • 10

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

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

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

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

  • 60

    在你的模型中:

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

    试试这个 .

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

    我找到了here .

    这是另一种方法 . 您要做的是在模型类上定义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
    

    以上代码来自here

  • 393

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

    假设它是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]
    

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

    希望有所帮助 .

  • 14

    带有完全本地化消息的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"
    
  • 4

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

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

    因为add_to_base已被弃用 .

    errors.add_to_base("Custom error message")

  • 16

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

    它可以让你做的事情:

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

    accepted answeranother answer down the list相关:

    我确认nanamkim's fork of 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

  • 7

    这是另一种方式:

    如果您使用此模板:

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

    这样,由于下划线,完整的消息变为" My custom message",但开头的额外空间是不明显的 . 如果你真的不想在开头有额外的空间,只需添加 .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不能为空”

  • 0

    按照正常的方式做到:

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

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

    en:
      errors:
        format: "%{message}"
    

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

  • 0

    如果你想将它们全部列在一个不错的列表中,但没有使用这个非常友好的名字,你可以这样做......

    object.errors.each do |attr,message|
      puts "<li>"+message+"</li>"
    end
    
  • 12

    在你看来

    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."
      }
    
  • 0

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

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

    这是我的代码,如果您仍然需要它可以对您有用:我的模型:

    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
    
  • 2

    如果您正在使用Rails-5您还可以使用以下内容:

    validates:user_name,presence:true,uniqueness:{message:“用户名已存在 . ”}

  • 58

    一种我从未见过的独特方法!

    我能够获得我想要的所有自定义的唯一方法是使用 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

相关问题