【问题标题】:How do I display Ruby on Rails form validation error messages one at a time?如何一次显示一条 Ruby on Rails 表单验证错误消息?
【发布时间】:2011-10-24 16:19:07
【问题描述】:

我正在尝试了解如何实现这一目标。谁能给我建议或指出正确的方向?

我目前所做的(如下面的代码 sn-p 所示)允许我一次显示每个字段的 1 个错误。这不完全是我想要做的。

我想一次显示 1 条错误消息。例如,“名字不能为空”,那么一旦解决了该错误,就会显示错误数组中的下一个错误。这应该会一直发生,直到所有错误都得到解决。

<% @user.errors.each do |attr, msg| %>
<%= "#{attr} #{msg}" if @user.errors[attr].first == msg %> 
<% end %>

【问题讨论】:

    标签: ruby-on-rails ruby rubygems


    【解决方案1】:

    ActiveRecord 将验证错误存储在一个名为 errors 的数组中。如果您有 User 模型,那么您将访问给定实例中的验证错误,如下所示:

    @user = User.create[params[:user]] # create will automatically call validators
    
    if @user.errors.any? # If there are errors, do something
    
      # You can iterate through all messages by attribute type and validation message
      # This will be something like:
      # attribute = 'name'
      # message = 'cannot be left blank'
      @user.errors.each do |attribute, message|
        # do stuff for each error
      end
    
      # Or if you prefer, you can get the full message in single string, like so:
      # message = 'Name cannot be left blank'
      @users.errors.full_messages.each do |message|
        # do stuff for each error
      end
    
      # To get all errors associated with a single attribute, do the following:
      if @user.errors.include?(:name)
        name_errors = @user.errors[:name]
    
        if name_errors.kind_of?(Array)
          name_errors.each do |error|
            # do stuff for each error on the name attribute
          end
        else
          error = name_errors
          # do stuff for the one error on the name attribute.
        end
      end
    end
    

    当然,如果您只想向用户显示第一个错误或其他内容,您也可以在视图而不是控制器中执行任何操作。

    【讨论】:

    • 我使用的是 Rails 4.2.0,你的代码对我不起作用。相反,我不得不从 @user.errors.invalid?(:name) 更改为 @user.errors.include?(:name)
    • 这是迄今为止我看到的关于堆栈溢出的最详细的答案。很棒。
    • 我在您使用的方法 '.on()' 上找不到任何文档。它没有出现在 ruby​​ 类“Hash”文档中?
    【解决方案2】:

    经过几个小时的实验,我想通了。

    <% if @user.errors.full_messages.any? %>
      <% @user.errors.full_messages.each do |error_message| %>
        <%= error_message if @user.errors.full_messages.first == error_message %> <br />
      <% end %>
    <% end %>
    

    更好:

    <%= @user.errors.full_messages.first if @user.errors.any? %>
    

    【讨论】:

    • 更好:&lt;%= f.object.errors.full_messages.join(", ") if f.object.errors.any? %&gt; - 这与对象和错误长度无关。 f 是表单变量。
    【解决方案3】:

    一个更好的主意,

    如果你想把错误信息放在文本字段的下面,你可以这样做

    .row.spacer20top
      .col-sm-6.form-group
        = f.label :first_name, "*Your First Name:"
        = f.text_field :first_name, :required => true, class: "form-control"
        = f.error_message_for(:first_name)
    

    什么是error_message_for
    --> 嗯,这是一个漂亮的 hack,可以做一些很酷的事情

    # Author Shiva Bhusal
    # Aug 2016
    # in config/initializers/modify_rails_form_builder.rb
    # This will add a new method in the `f` object available in Rails forms
    class ActionView::Helpers::FormBuilder
      def error_message_for(field_name)
        if self.object.errors[field_name].present?
          model_name              = self.object.class.name.downcase
          id_of_element           = "error_#{model_name}_#{field_name}"
          target_elem_id          = "#{model_name}_#{field_name}"
          class_name              = 'signup-error alert alert-danger'
          error_declaration_class = 'has-signup-error'
    
          "<div id=\"#{id_of_element}\" for=\"#{target_elem_id}\" class=\"#{class_name}\">"\
          "#{self.object.errors[field_name].join(', ')}"\
          "</div>"\
          "<!-- Later JavaScript to add class to the parent element -->"\
          "<script>"\
              "document.onreadystatechange = function(){"\
                "$('##{id_of_element}').parent()"\
                ".addClass('#{error_declaration_class}');"\
              "}"\
          "</script>".html_safe
        end
      rescue
        nil
      end
    end
    

    结果

    错误后生成的标记

    <div id="error_user_email" for="user_email" class="signup-error alert alert-danger">has already been taken</div>
    <script>document.onreadystatechange = function(){$('#error_user_email').parent().addClass('has-signup-error');}</script>
    

    对应的SCSS

      .has-signup-error{
        .signup-error{
          background: transparent;
          color: $brand-danger;
          border: none;
        }
    
        input, select{
          background-color: $bg-danger;
          border-color: $brand-danger;
          color: $gray-base;
          font-weight: 500;
        }
    
        &.checkbox{
          label{
            &:before{
              background-color: $bg-danger;
              border-color: $brand-danger;
            }
          }
        }
    

    注意:此处使用的引导变量

    【讨论】:

      【解决方案4】:

      我是这样解决的:

      <% @user.errors.each do |attr, msg| %>
        <li>
          <%= @user.errors.full_messages_for(attr).first if @user.errors[attr].first == msg %>
        </li>
      <% end %>
      

      这样您就可以使用语言环境来显示错误消息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-08
        • 2022-01-26
        • 1970-01-01
        • 2013-10-07
        • 2011-02-03
        • 1970-01-01
        • 2019-04-11
        • 1970-01-01
        相关资源
        最近更新 更多