2011-10-24 11 views
32

Sto cercando di capire come ottenerlo. Qualcuno può consigliarmi o indicarmi la giusta direzione?Come visualizzare i messaggi di errore di convalida di Ruby on Rails uno alla volta

Ciò consente di visualizzare 1 errore per ciascun campo alla volta. È quasi ciò che voglio fare, ma non esattamente. Voglio visualizzare 1 intero messaggio di errore alla volta. PER ESEMPIO. il nome non può essere vuoto. Una volta risolto, passa all'errore successivo. Quindi, se l'utente aggiungeva numeri al loro cognome, non sarebbe più vuoto, ma mostrerebbe un altro errore affermando che solo le lettere erano permesse, ecc. Quando l'errore era stato risolto, sarebbe passato all'errore del cognome o forse alla posta elettronica se il campo dell'utente il loro cognome correttamente.

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

risposta

26

Dopo aver sperimentato per alcune ore ho capito.

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

Ancora meglio:

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

Ancora meglio: '<% = f.object.errors.full_messages.join (", ") if f.object.errors.any? %> '- questo è oggetto e lunghezza della lunghezza dell'errore. 'f' è la variabile di forma. –

48

ActiveRecord errori negozi convalida in un array chiamato errors. Se si dispone di un modello User allora si potrebbe accedere gli errori di convalida in una determinata istanza in questo modo:

@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 

Naturalmente si può anche fare nulla di tutto questo il punto di vista invece del controllore, se si desidera visualizzare solo il primo errore per l'utente o qualcosa del genere.

+2

Sto usando Rails 4.2.0 e il tuo codice non ha funzionato per me. Invece dovevo cambiare da '@ user.errors.invalid? (: Name)' a '@ user.errors.include? (: Name)' – anka

+0

Questa è la risposta più dettagliata che ho visto sullo stack overflow fino ad ora.Eccellente. –

+0

Non riesco a trovare alcun documento sul tuo metodo usato '.on()'. Non compare nella classe "Hash" del ruby ​​doc? – Douglas

5

Un'idea migliore,

se si vuole mettere il messaggio di errore appena sotto il campo di testo, si può fare in questo modo

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

Che cos'è error_message_for?
-> Beh, questo è un bellissimo trucco per fare un po 'roba fresca

# 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 

Risultato enter image description here

Markup generato dopo errore

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

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

Nota: Bootstrap variabili utilizzate qui

1

ho risolto in questo modo:

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

In questo modo si stanno utilizzando i locali per i messaggi di errore.

Problemi correlati