rails – Devise – Handling – devise_error_messages

nella mia pagina di modifica utente, c’è una riga come segue:

 

Il problema è che questo non genera errori nel modo standard utilizzato dal resto dell’app:

  <div class="flash ">

La mia domanda è, come faccio a far funzionare il messaggio di errore di sviluppo come gli altri che usano flash.each?

Grazie.

Sto cercando di capirlo da solo. Ho appena trovato questo problema registrato su Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788

Jose sta dicendo che devise_error_messsages! il metodo è solo uno stub (sebbene contenga un’implementazione) e che dovremmo sovrascrivere / sostituire. Sarebbe stato bello se fosse stato indicato da qualche parte nel wiki, ed è per questo che credo che ci siano alcune persone come noi che hanno indovinato.

Quindi ho intenzione di provare a riaprire il modulo e ridefinire il metodo, ignorando in modo efficace l’implementazione predefinita. Ti farò sapere come va.

Aggiornare

Sì, funziona. Ho creato app/helpers/devise_helper.rb e lo sovrascrivo in questo modo:

 module DeviseHelper def devise_error_messages! 'KABOOM!' end end 

Quindi, sapendo questo, posso modificare il metodo per visualizzare i messaggi di errore nel modo in cui lo voglio.

Per aiutarti a risolvere il tuo problema originale: ecco l’originale devise_helper.rb su Github . Guarda come vengono attraversati i messaggi di errore:

 messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join 

Questo dovrebbe aiutarti a iniziare. 🙂

Un altro aggiornamento

L’object resource è in realtà il modello che viene utilizzato da devise (vai alla figura).

 resource.class #=> User resource.errors.class #=> ActiveModel::Error 

Sembra anche essere definito in un ambito più elevato (probabilmente proveniente dal controller), quindi è ansible accedervi in ​​una varietà di luoghi.

Ovunque nel tuo Helper

 module DeviseHelper def devise_error_messages1! resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join end def devise_error_messages2! resource.errors.full_messages.map { |msg| content_tag(:p, msg) }.join end end 

Il tuo punto di vista

 
<%= resource.errors.inspect %>

Di seguito la soluzione funziona con le ultime novità di oggi (4.1.1) e Rails 4.2.6. Ma è così semplice che non vedo il motivo per cui non funzionerebbe tra 10 anni a partire da ora)

Se vuoi riciclare i tuoi messaggi di errore e farli sembrare uguali nella tua app, ti consiglierei qualcosa di simile (come ho imparato con Michael Hartl tut):

Crea partial per i messaggi di errore: layouts/_error_messages.html.erb Inserisci il seguente codice (qui uso alcune classi bootstrap 3):

 <% if object.errors.any? %> 

This form contains <%= pluralize(object.errors.count, 'error') %>.

    <% object.errors.full_messages.each do |msg| %>
  • <%= msg %>
  • <% end %>
<% end %>

Ora hai qualcosa di riciclabile e puoi usarlo su tutta la linea. Invece di idea standard:

 <%= devise_error_messages! %> 

Chiamalo nel tuo modulo in questo modo:

 <%= render 'layouts/error_messages', object: resource %> 

Puoi metterlo in qualsiasi forma. Invece di passare la risorsa devise puoi passare una variabile dal tuo modulo in questo modo:

 <%= form_for @post do |f| %> <%= render 'layouts/error_messages', object: f.object %> <%= f.text_field :content %> <%= f.submit %> <% end %> 

So che è passato un po ‘di tempo da quando è stata pubblicata questa domanda, ma volevo solo commentare ciò che ho trovato. Le due persone che hanno già risposto sono state di grande aiuto per me e volevo solo contribuire.

Vedrai in Devise che ci sono chiamate usando render_with_scope . Credo che questo sia un metodo definito da Devise e fondamentalmente applica l’attuale scope alla successiva vista renderizzata.

Perché è rilevante? Devise contiene i tuoi errori all’interno di resource.errors ( non @resource.errors ). Devise funziona bene se vuoi usarlo fuori dalla scatola, per così dire.

I problemi con questi errori si verificano se si inizia a modificare il comportamento di gestione degli utenti. Aggiungendo un redirect_to o render (invece di render_with_scope ) dove render_with_scope precedenza non ne aveva uno, in pratica stai buttando fuori i messaggi di errore. A mio avviso, Devise è scortese da modificare.

La mia soluzione è questa

 # In application.html.erb <% flash.each do |name, msg| %> # New code (allow for flash elements to be arrays) <% if msg.class == Array %> <% msg.each do |message| %> <%= content_tag :div, message, :id => "flash_#{name}" %> <% end %> <% else %> # old code <%= content_tag :div, msg, :id => "flash_#{name}" %> <% end %> #don't forget the extra end <% end %> 

e

 # Wherever you want Devise's error messages to be handled like # your other error messages # (in my case, registrations_controller.rb, a custom controller) flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages 

Quest’ultimo blocco di codice prende i messaggi di errore di Devise come una matrice e lo aggiunge a flash[:notice] (come array). Ogni messaggio verrà stampato una riga alla volta. Se avrò il tempo, penso che cambierò il modo in cui Devise gestisce i messaggi di errore per farlo nella mia app, poiché sembra molto più pulito avere un sistema di messaggi di errore invece di due.

Voglio solo portare un nuovo piccolo pezzo qui:

Così ho trovato un modo più semplice per ottenere il risultato desiderato da “AnApprentice”.

Prima di tutto, se vuoi personalizzare qualcosa all’interno del plug-in Devise, ti consiglio vivamente di copiare il codice da “\ Ruby_repertory \ lib \ ruby ​​\ gems \ 1.9.1 \ gems \ devise-version \ app \ controller | helpers | mailers … “al file che vuoi nel tuo progetto.

[Modifica] Oppure puoi rendere il tuo file ereditato dai file di configurazione “normali” … Come … per esempio … Vuoi sovrascrivere solo una funzione all’interno di devise / registrations_controller.rb, la prima riga della tua user Custom il controllore delle registrazioni sarebbe:

 class Users::RegistrationsController < Devise::RegistrationsController 

[Modifica 7 agosto 2013] Now Devise fornisce anche uno strumento per generare controller: https://github.com/plataformatec/devise/wiki/Tool:-Generate-and-customize-controllers

Quindi ... comunque ... sono riuscito a ottenere ciò che "AnApprentice" voleva solo scrivere (per una soluzione più pulita, vedere la seguente modifica):

 #/my_project/app/helpers/devise_helper.rb module DeviseHelper def devise_error_messages! return "" if resource.errors.empty? return resource.errors end end 

E, a mio avviso, le linee successive hanno funzionato piuttosto bene:

 <% devise_error_messages!.each do |key, value| %> 
<%= key %> <%= value %>
<% end %>

Bene ... allora puoi accedere agli errori per un attributo specifico come questo:

  #Imagine you want only the first error to show up for the login attribute: <%= devise_error_messages![:login].first %> 

E ... Un piccolo trucco per avere un solo errore (il primo ad essere catturato) che mostra per attributo:

 <% if resource.errors.any? %> <% saved_key = "" %> <% devise_error_messages!.each do |key, value| %> <% if key != saved_key %> 
<%= key %> <%= value %>
<% end %> <% saved_key = key %> <% end %> <% end %>

So che è passato un po 'di tempo da quando è stata pubblicata questa domanda, ma penso che aiuterà molti utenti di ideare :).

Big Edit:

Poiché amo estendere il mio codice, renderlo più pulito e condividerlo con gli altri, recentemente ho voluto modificare i messaggi devise_error_messages! metodo per usarlo nelle mie viste e farlo visualizzare il trucco che ho spiegato sopra.

Quindi, ecco il mio metodo:

  def devise_error_messages! html = "" return html if resource.errors.empty? errors_number = 0 html << "
    " saved_key = "" resource.errors.each do |key, value| if key != saved_key html << "
  • This #{key} #{value}
  • " errors_number += 1 end saved_key = key end unsolved_errors = pluralize(errors_number, "unsolved error") html = "

    You have #{unsolved_errors}

    " + html html << "
" return html.html_safe end

Non è un grosso problema qui, ho riutilizzato il codice che ho scritto a mio avviso per mostrare solo un attributo error pey, perché spesso il primo è l'unico rilevante (come quando l'utente dimentica un campo obbligatorio).

Sto contando quegli errori "unici" e sto facendo un titolo H2 HTML usando pluralize e mettendolo PRIMA dell'elenco degli errori.

Quindi ora posso usare "devise_error_messages!" come quello predefinito e restituisce esattamente ciò che stavo già mostrando prima.

Se si desidera accedere a un messaggio di errore specifico nella propria vista, ora consiglio di utilizzare direttamente "resource.errors [: attribute] .first" o qualsiasi altra cosa.

Seya, Kulgar.

Ho risolto questo modo in modo simile a YoyoS, creando app/helpers/devise_helper.rb e inserendola al suo interno:

 module DeviseHelper # Hacky way to translate devise error messages into devise flash error messages def devise_error_messages! if resource.errors.full_messages.any? flash.now[:error] = resource.errors.full_messages.join(' & ') end return '' end end 

Lavorato!

Sto usando Devise in Rails 3 e il tuo codice flash è praticamente identico a quello che ho. Nella mia app, il codice funziona come previsto; Ad esempio, i messaggi di errore Devise vengono emessi con il resto dei miei messaggi flash:

 <% flash.each do |name, msg| %> <%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %> <% end %> 

Prova questo codice esatto e verifica se fa alcuna differenza: il diverso attributo ID può essere d’aiuto.

Mi sono avvicinato a questo e sta funzionando finora. Ciò aggiunge messaggi flash al flash, quindi può essere usato come al solito. Per favore considera che sono nuovo di Ruby e Rails …

 class ApplicationController < ActionController::Base after_filter :set_devise_flash_messages, :if => :devise_controller? ... private: def set_devise_flash_messages if resource.errors.any? flash[:error] = flash[:error].to_a.concat resource.errors.full_messages flash[:error].uniq! end end end 

Modificare:

Scusa se stavo facendo la guardia e alcuni comportamenti indesiderati erano presenti. Poiché after_filter viene chiamato dopo il rendering, quindi non funziona come previsto. Se qualcuno sa come chiamare un metodo dopo l’azione ma prima del rendering …

Ma puoi usare qualcosa del genere, invece:

 module ApplicationHelper # merge the devise messages with the normal flash messages def devise_flash if controller.devise_controller? && resource.errors.any? flash.now[:error] = flash[:error].to_a.concat resource.errors.full_messages flash.now[:error].uniq! end end end 

In views/shared/_messages.html.erb

 <% devise_flash %>  

Se vuoi essere in grado di visualizzare più di un flash di un determinato tipo (: alert,: notice, ecc …) e non sprecare tempo a cercare di modificare un comportamento gem, questa è la soluzione che ho usato con Devise. Sono abbastanza sicuro che potrebbe essere utilizzato con qualsiasi gem che utilizza i messaggi flash.

Per prima cosa, nel tuo application_controller.rb, aggiungi questo:

  # Adds the posibility to have more than one flash of a given type def flash_message(type, text) flash[type] ||= [] flash[type] << text end 

La seconda cosa da fare, visualizzando i messaggi flash con questo in application.html.erb (o ovunque tu voglia):

  
<% flash.each do |key, messages| %> <% messages = Array(messages) unless messages.is_a?(Array) %> <% messages.each do |message| %>
<%= message %>
<% end %> <% end %>

La terza cosa da fare, ogni volta che vuoi aggiungere un messaggio flash in qualsiasi controller, fai questo:

 flash_message(:success, "The user XYZ has been created successfully.") 

Effettivamente, un po ‘hacky, ma sto usando questo helper (app / helpers / devise_helper.rb) per catturare i flash e usarli se impostati e quindi default su resource.errors . Questo si basa solo sull’aiutante che si trova nella versione di sviluppo.

 module DeviseHelper def devise_error_messages! flash_alerts = [] error_key = 'errors.messages.not_saved' if !flash.empty? flash_alerts.push(flash[:error]) if flash[:error] flash_alerts.push(flash[:alert]) if flash[:alert] flash_alerts.push(flash[:notice]) if flash[:notice] error_key = 'devise.failure.invalid' end return "" if resource.errors.empty? && flash_alerts.empty? errors = resource.errors.empty? ? flash_alerts : resource.errors.full_messages messages = errors.map { |msg| content_tag(:li, msg) }.join sentence = I18n.t(error_key, :count => errors.count, :resource => resource.class.model_name.human.downcase) html = <<-HTML 

#{sentence}

    #{messages}
HTML html.html_safe end end

Se stai cercando di utilizzare i devise_error_messages, puoi farlo aggiungendo a resource.errors

Se dovessi superare il controller di registrazione, potrebbe sembrare

 def create if validation_or_other_check_passes super else build_resource clean_up_passwords(resource) resource.errors.add(:notice, "The check failed.") render :new 

Modo molto semplice per visualizzare un messaggio di errore per ogni campo

 <%= resource.errors.messages[:email].join(" ") %> 

inserire per ciascun campo il nome del campo in parentesi quadra sotto ogni riga in cui si desidera visualizzare il messaggio di errore in linea.

lo faccio semplicemente, ho lavorato per me: in app / helpers / , creo un file devise_helper.rb

  module DeviseHelper def devise_error_messages_for(resource) return "" if resource.errors.empty? messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join sentence = I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase) html = <<-HTML 

#{sentence}

    #{messages}
HTML html.html_safe end end

in tutti i file di vista che cambio

 <%= devise_error_messages! %> 

per:

 <%= devise_error_messages_for(#your object in your formular)%> 

per me è a mio avviso modificare e nuovo utente:

  <%=form_for resource, as: @user, url: user_path(@user),... <%= devise_error_messages_for(@user) %> 

spero che ti possa aiutare;)

Per mostrare il tuo errore di progettazione dal tuo controller con solo il primo errore da mostrare.

 flash[:error] = @resource.errors.full_messages.first 

Solo per aggiungere a Eric Hu la risposta sopra in cui sono usate tutte le istruzioni If, piuttosto fare qualcosa di simile.

 # Controller flash.now[:error] = flash[:error].to_a.concat(resource.errors.full_messages) # View <% flash.each do |name, msg| %> <% Array(msg).uniq.each do |message| %> <%= message %> <% end %> <% end %> 
  1. Rimuovi “devise_error_messages!” dal modello “app / visualizzazioni / utenti / password / nuovo”.
  2. Crea un controller personalizzato per il tuo utente (app / controller / utenti / password_controller.rb) e in un filtro successivo aggiungi errori array flash:
 class Users::PasswordsController < Devise::PasswordsController after_filter :flash_errors def flash_errors unless resource.errors.empty? flash[:error] = resource.errors.full_messages.join(", ") end end end 

Mi piace farlo proprio come è fatto nell’altro controller di Devise con questo cheat.

 <% if flash.count > 0 %> 

Errors prevented you from logging in

    <% flash.each do |name, msg| %>
  • <%= content_tag :div, msg, id: "flash_#{name}" %>
  • <% end %>
<% end %>

Per materialisecss visualizzare i messaggi di errore devise come toast ho aggiunto questo codice in app / helpers / devise_helper.rb

 module DeviseHelper def devise_error_messages! messages = resource.errors.full_messages.map { |msg| String.new(" M.toast({html: '" + msg + "' }); ".html_safe ) }.join messages = ("").html_safe end end 

Sono sicuro che il loro sarebbe il modo più pulito per scriverlo, ma sta funzionando perfettamente

Ho appena creato app/helpers/devise_helper.rb come John, ma app/helpers/devise_helper.rb sovrascritto il metodo in questo modo:

 module DeviseHelper def devise_error_messages! flash[:error] = resource.errors.full_messages.join('
') return '' end end

Con questo non devo modificare nient’altro. È una ctriggers idea? Sono nuovo alle rotaie, non esitare a correggermi. Grazie.

Ho appena dichiarato devise_error_messages! come un aiutante vuoto. E recuperato e gestito manualmente gli errori in un partial _errors parziale per la mia applicazione. Sembrava la soluzione più semplice e non devo passare attraverso tutti i file di devise e rimuovere la chiamata al gestore degli errori.