2011-10-24 40 views
32

Tôi đang cố gắng hiểu cách tôi có thể đạt được điều này. Bất cứ ai có thể tư vấn cho tôi hoặc chỉ cho tôi đi đúng hướng?Cách hiển thị thông báo lỗi xác thực biểu mẫu Ruby on Rails cùng một lúc

Điều này cho phép 1 lỗi từ mỗi trường hiển thị cùng một lúc. Đó là gần như những gì tôi muốn làm nhưng không hoàn toàn chính xác. Tôi muốn hiển thị toàn bộ 1 thông báo lỗi tại một thời điểm. VÍ DỤ. tên đầu tiên không được để trống. Khi điều đó đã được giải quyết, nó sẽ chuyển sang lỗi tiếp theo. Vì vậy, nếu người dùng thêm số vào họ của họ, nó sẽ không được để trống nữa nhưng nó sẽ hiển thị lỗi khác chỉ ghi rõ chữ cái được cho phép. Khi lỗi đó được sửa, nó sẽ đến lỗi cuối cùng hoặc có thể email nếu trường người dùng ra họ của họ một cách chính xác.

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

Trả lời

26

Sau khi thử nghiệm trong vài giờ, tôi đã tìm ra.

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

Thậm chí tốt hơn:

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

Thậm chí tốt hơn: '<% = f.object.errors.full_messages.join (", ") nếu f.object.errors.any? %> '- đây là đối tượng và độ dài lỗi bất khả tri. 'f' là biến dạng. –

48

ActiveRecord lưu lỗi xác thực trong một mảng gọi là errors. Nếu bạn có một mô hình User sau đó bạn sẽ truy cập vào các lỗi xác nhận trong một trường hợp nhất định như vậy:

@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.on(: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 

Tất nhiên bạn cũng có thể làm bất cứ điều này trong các quan điểm thay vì bộ điều khiển, bạn nên muốn chỉ hiển thị lỗi đầu tiên cho người dùng hoặc một cái gì đó.

+2

Tôi đang sử dụng Rails 4.2.0 và mã của bạn không hoạt động đối với tôi. Thay vào đó tôi phải thay đổi từ '@ user.errors.invalid? (: Name)' thành '@ user.errors.include? (: Name)' – anka

+0

Đây là câu trả lời chi tiết nhất mà tôi đã thấy trên stack overflow cho đến nay.Xuất sắc. –

+0

Tôi không thể tìm thấy bất kỳ tài liệu nào về phương thức đã sử dụng '.on()' của bạn. Nó không xuất hiện trong lớp ruby ​​"Hash" doc? – Douglas

5

Một ý tưởng tốt hơn,

nếu bạn muốn đưa thông báo lỗi ngay dưới trường văn bản, bạn có thể làm như thế này

.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?
-> Vâng, đây là một hack đẹp để làm một số công cụ mát

# 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 

quả enter image description here

Markup tạo sau lỗi

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

Tương ứng 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; 
     } 
     } 
    } 

Lưu ý: Bootstrap biến sử dụng ở đây

1

tôi giải quyết nó như thế này:

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

Bằng cách này bạn đang sử dụng miền địa phương cho các thông báo lỗi.

Các vấn đề liên quan