How do I display Ruby on Rails form validation error messages one at a time?

前端 未结 4 526
梦谈多话
梦谈多话 2020-12-02 14:12

I\'m trying to understand how I can achieve this. Can anyone advise me or point me in the right direction?

What I currently do, which is shown in the code snippet be

相关标签:
4条回答
  • 2020-12-02 14:58

    A better idea,

    if you want to put the error message just beneath the text field, you can do like this

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

    What is error_message_for?
    --> Well, this is a beautiful hack to do some cool stuff

    # 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
    

    Result

    Markup Generated after error

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

    Corresponding 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;
            }
          }
        }
    

    Note: Bootstrap variables used here

    0 讨论(0)
  • 2020-12-02 15:04

    After experimenting for a few hours I figured it out.

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

    Even better:

    <%= @user.errors.full_messages.first if @user.errors.any? %>
    
    0 讨论(0)
  • 2020-12-02 15:07

    I resolved it like this:

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

    This way you are using the locales for the error messages.

    0 讨论(0)
  • 2020-12-02 15:10

    ActiveRecord stores validation errors in an array called errors. If you have a User model then you would access the validation errors in a given instance like so:

    @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
    

    Of course you can also do any of this in the views instead of the controller, should you want to just display the first error to the user or something.

    0 讨论(0)
提交回复
热议问题