Как отображать сообщения об ошибках проверки формы Ruby on Rails по одному - PullRequest
38 голосов
/ 24 октября 2011

Я пытаюсь понять, как я могу этого достичь.Кто-нибудь может посоветовать мне или указать мне правильное направление?

Это позволяет отображать по 1 ошибке из каждого поля за раз.Это почти то, что я хочу сделать, но не совсем точно.Я хочу отображать 1 сообщение об ошибке за раз.Например, имя не может быть пустым.Как только это было решено, оно переходит к следующей ошибке.Таким образом, если бы пользователь добавил цифры к своей фамилии, она больше не была бы пустой, но показывала бы другую ошибку, указывающую, что разрешены только буквы и т. Д. Когда эта ошибка будет исправлена, она перейдет к ошибке фамилии или, возможно, к электронной почте, если поле пользователяправильно указать их фамилию.

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

Ответы [ 4 ]

62 голосов
/ 24 октября 2011

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

Конечно, вы также можете делать все это в представлениях вместо контроллера, если вамхотите просто отобразить первую ошибку пользователю или что-то в этом роде.

29 голосов
/ 24 октября 2011

После нескольких часов экспериментов я понял это.

<% 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? %>
8 голосов
/ 12 августа 2016

Лучшая идея,

, если вы хотите поместить сообщение об ошибке прямо под текстовым полем, вы можете сделать это следующим образом:

.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?
-> Ну, это прекрасный взлом, чтобы делать классные вещи

# 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

Результат enter image description here

Разметка Генерируется после ошибки

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

Примечание: здесь используются переменные начальной загрузки

2 голосов
/ 03 января 2017

Я решил это так:

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

Таким образом, вы используете локали для сообщений об ошибках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...