ruby on rails - español - rails-Devise-Manejo-devise_error_messages
devise rails español (19)
- Eliminar el "devise_error_messages!" de la plantilla "app / views / users / passwords / new".
- Cree un controlador personalizado para su usuario (app / controllers / users / passwords_controller.rb) y en un filtro posterior agregue los errores de matriz 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
en mi página de edición de usuario, hay una línea de la siguiente manera:
<%= devise_error_messages! %>
El problema es que esto no genera errores de la manera estándar que el resto de la aplicación:
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
Mi pregunta es, ¿cómo hago para que el mensaje de error de diseño funcione como los otros que usan el flash.each?
Gracias.
¡Acabo de declarar devise_error_messages! como un ayudante vacío. Y busqué y manejé manualmente los errores en un _verrors general parcial para mi aplicación. Parecía la solución más simple y no tenía que pasar por todos los archivos del dispositivo y eliminar la llamada al controlador de errores.
Acabo de crear una app/helpers/devise_helper.rb
como John, pero eliminé el método de esa manera:
module DeviseHelper
def devise_error_messages!
flash[:error] = resource.errors.full_messages.join(''<br />'')
return ''''
end
end
Con esto no tengo que modificar nada más. Es una mala idea ? Soy nuevo en los rieles, no dude en corregirme. Gracias.
Es cierto que es un poco hacky, pero estoy usando este helper (app / helpers / devise_helper.rb) para tomar destellos y usarlos si está configurado, por defecto, en resource.errors
. Esto solo se basa en el ayudante que está en la ide de lib.
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
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
Estoy intentando resolver esto yo mismo. Acabo de encontrar este problema en Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788
¡José dice que devise_error_messsages!
El método es solo un trozo (aunque contiene una implementación) y se supone que debemos anularlo / reemplazarlo. Hubiera sido bueno si esto se señaló en algún lugar de la wiki, que es por lo que creo que hay algunas personas como nosotros que han estado adivinando.
Así que voy a tratar de volver a abrir el módulo y redefinir el método, anulando de manera efectiva la implementación predeterminada. Te dejaré saber cómo va.
Actualizar
Sí, eso funciona. app/helpers/devise_helper.rb
y la app/helpers/devise_helper.rb
así:
module DeviseHelper
def devise_error_messages!
''KABOOM!''
end
end
Entonces, sabiendo esto, puedo modificar el método para mostrar mensajes de error de la manera que quiero.
Para ayudarlo a resolver su problema original: Aquí está el original devise_helper.rb
en Github . Observe cómo se atraviesan los mensajes de error:
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
Eso debería ayudarte a comenzar. :)
Otra actualización
El objeto de resource
es en realidad el modelo que está utilizando el dispositivo (figura).
resource.class #=> User
resource.errors.class #=> ActiveModel::Error
También parece estar definido en un ámbito superior (probablemente proveniente del controlador), por lo que se puede acceder en una variedad de lugares.
En cualquier lugar de tu 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
Su vista
<div><%= resource.errors.inspect %></div>
Estoy usando Devise in Rails 3 y tu código de flash es bastante idéntico al que tengo. En mi aplicación, el código funciona como se esperaba; es decir, los mensajes de error de Devise se emiten con el resto de mis mensajes flash:
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>
Pruebe este código exacto y vea si hace alguna diferencia: los diferentes atributos de ID pueden ayudar.
La siguiente solución funciona con el último dispositivo a partir de ahora (4.1.1) y Rails 4.2.6. Pero es tan simple que no veo la razón por la cual no funcionaría dentro de 10 años;)
Si desea reciclar sus mensajes de error y hacer que se vean iguales en su aplicación, le recomendaría algo como esto (tal como lo aprendí con Michael Hartl tut):
Cree mensajes parciales de error: layouts/_error_messages.html.erb
Ponga el siguiente código (aquí uso algunas clases de bootstrap 3):
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<p><strong>This form contains <%= pluralize(object.errors.count, ''error'') %>.</strong></p>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
Ahora tiene algo reciclable y puede usarlo en todos los ámbitos. En lugar de diseño estándar:
<%= devise_error_messages! %>
Llámalo en tu forma así:
<%= render ''layouts/error_messages'', object: resource %>
Puedes ponerlo en cualquier forma. En lugar de pasar el recurso de diseño, puede pasar la variable de su formulario de esta manera:
<%= form_for @post do |f| %>
<%= render ''layouts/error_messages'', object: f.object %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
Llegué a esto y está funcionando hasta ahora. Eso agrega diseñar mensajes para el flash, por lo que se puede utilizar como de costumbre. Por favor, considere que soy nuevo en Ruby and 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
Editar:
Lo siento, estaba haciendo guardia y estaba presente algún comportamiento no deseado. Desde after_filter
se llama después de la representación, por lo que no funciona como se esperaba. Si alguien sabe cómo llamar a un método después de la acción, pero antes de la prestación ...
Pero puedes usar algo como eso en su lugar:
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
En views/shared/_messages.html.erb
<% devise_flash %>
<!-- then display your flash messages as before -->
Lo resolví de manera similar a YoyoS, creando una app/helpers/devise_helper.rb
y colocando esto en ella:
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
¡Trabajó!
Me gusta hacerlo tal como se hace en el otro controlador Devise con este truco.
<% if flash.count > 0 %>
<div id="error_explanation">
<h2>Errors prevented you from logging in</h2>
<ul>
<% flash.each do |name, msg| %>
<li>
<%= content_tag :div, msg, id: "flash_#{name}" %>
</li>
<% end %>
</ul>
</div>
<% end %>
Muy fácil manera de mostrar el mensaje de error para cada campo
<%= resource.errors.messages[:email].join(" ") %>
poner para cada campo con el nombre del campo entre corchetes debajo de cada línea donde desee mostrar un mensaje de error en línea.
Para mostrar su error de diseño de su controlador, solo aparece el primer error.
flash[:error] = @resource.errors.full_messages.first
Para que materialisecss muestre los mensajes de error como tostados agregué este código en la aplicación / 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 = ("<script>" + messages + "</script>").html_safe
end
end
Estoy seguro de que sería la forma más limpia de escribirlo, pero funciona perfectamente
Sé que ha pasado un tiempo desde que se publicó esta pregunta, pero solo quería comentar sobre lo que he encontrado. Las dos personas que ya respondieron me han sido de gran ayuda y solo quería contribuir.
Verás a lo largo de Idee que hay llamadas que usan render_with_scope
. Creo que este es un método definido por el diseño y básicamente aplica el alcance actual a la siguiente vista representada.
¿Por qué es esto relevante? Devise contiene sus errores dentro de resource.errors
( no @resource.errors
). Devise funciona bien si quiere usarlo de la caja, por así decirlo.
Los problemas con estos errores surgen si comienza a cambiar su comportamiento de administración de usuarios. Al agregar un redirect_to
o render
(en lugar de render_with_scope
) donde Devise anteriormente no tenía uno, básicamente está descartando los mensajes de error. Esto hace que Devise sea poco amistoso a la modificación, en mi opinión.
Mi solución es esta
# 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 %>
y
# 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
El último bloque de código toma los mensajes de error de Devise como una matriz y lo agrega a flash[:notice]
(como una matriz). Cada mensaje se imprimirá una línea a la vez. Si tengo tiempo, creo que voy a cambiar cómo maneja Devise los mensajes de error para hacer esto a través de mi aplicación, ya que parece mucho más limpio tener un sistema de mensajes de error en lugar de dos.
Si desea poder mostrar más de un flash de un tipo determinado (: alerta,: aviso, etc.) y no perder el tiempo tratando de modificar el comportamiento de una gema, esta es la solución que utilicé con Devise. Estoy bastante seguro de que podría usarse con cualquier gema que use mensajes flash.
Lo primero que debe hacer, en su application_controller.rb, agregue esto:
# Adds the posibility to have more than one flash of a given type
def flash_message(type, text)
flash[type] ||= []
flash[type] << text
end
Lo segundo que hacer es mostrar tus mensajes flash con esto en application.html.erb (o donde quieras):
<div class="flashes">
<% flash.each do |key, messages| %>
<% messages = Array(messages) unless messages.is_a?(Array) %>
<% messages.each do |message| %>
<div class="alert alert-<%= key %>">
<%= message %>
</div>
<% end %>
<% end %>
</div>
Tercero, siempre que desee agregar un mensaje flash en cualquier controlador, haga esto:
flash_message(:success, "The user XYZ has been created successfully.")
Si está buscando anexarse a devise_error_messages, puede hacerlo agregando a resource.errors
Si fuera a montar el controlador de registro, podría parecerse
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
Simplemente hago esto, funcionó para mí: en la aplicación / helpers / , creo un archivo 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
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
en todos los archivos de vista cambio
<%= devise_error_messages! %>
para:
<%= devise_error_messages_for(#your object in your formular)%>
para mí, en mi opinión, editar y un nuevo usuario:
<%=form_for resource, as: @user, url: user_path(@user),...
<%= devise_error_messages_for(@user) %>
Espero que te ayude ;)
Solo para agregar a Eric Hu, respuesta anterior donde se usan todas las declaraciones If, en vez de eso, haga algo como esto.
# 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 %>
Solo quiero traer una nueva pieza aquí:
Así que encontré una manera más fácil de obtener el resultado que quería "AnApprentice".
En primer lugar, si desea personalizar cualquier cosa dentro del complemento Devise, le recomiendo que copie el código de "/ Ruby_repertory / lib / ruby / gems / 1.9.1 / gems / devise-version / app / controllers" | helpers | mailers ... "al archivo que desea en su proyecto.
[Editar] O puede hacer que su archivo herede de los archivos de diseño "normal" ... Como ... decir ... Usted desea sobrescribir solo una función dentro del dispositivo / registrations_controller.rb, la primera línea de sus usuarios personalizada el controlador de registros sería:
class Users::RegistrationsController < Devise::RegistrationsController
[Editar el 7 de agosto de 2013] Ahora, Devise incluso proporciona una herramienta para generar controladores: https://github.com/plataformatec/devise/wiki/Tool:-Generate-and-customize-controllers
Entonces ... de todos modos ... Logré obtener lo que "AnApprentice" quería solo escribir esto (para una solución más limpia, vea la siguiente gran edición):
#/my_project/app/helpers/devise_helper.rb
module DeviseHelper
def devise_error_messages!
return "" if resource.errors.empty?
return resource.errors
end
end
Y, en mi opinión, las siguientes líneas funcionaron bastante bien:
<% devise_error_messages!.each do |key, value| %>
<div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
Bueno ... entonces puedes acceder a los errores de un atributo específico como este:
#Imagine you want only the first error to show up for the login attribute:
<%= devise_error_messages![:login].first %>
Y ... Un pequeño truco para tener solo un error (el primero en quedar atrapado) que aparece por atributo:
<% if resource.errors.any? %>
<% saved_key = "" %>
<% devise_error_messages!.each do |key, value| %>
<% if key != saved_key %>
<div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
<% saved_key = key %>
<% end %>
<% end %>
Sé que ha pasado un tiempo desde que se publicó esta pregunta, pero creo que ayudará mucho a los usuarios del diseño :).
Gran Edición:
Como me encanta extender mi código, hacerlo más limpio y compartirlo con otros, ¡recientemente quise cambiar el devise_error_messages! método para usarlo en mis puntos de vista y hacer que muestre el truco que expliqué anteriormente.
Entonces, aquí está mi método:
def devise_error_messages!
html = ""
return html if resource.errors.empty?
errors_number = 0
html << "<ul class=/"#{resource_name}_errors_list/">"
saved_key = ""
resource.errors.each do |key, value|
if key != saved_key
html << "<li class=/"#{key} error/"> This #{key} #{value} </li>"
errors_number += 1
end
saved_key = key
end
unsolved_errors = pluralize(errors_number, "unsolved error")
html = "<h2 class=/"#{resource_name}_errors_title/"> You have #{unsolved_errors} </h2>" + html
html << "</ul>"
return html.html_safe
end
No es gran cosa, reutilicé el código que escribí en mi vista para mostrar solo un atributo pey de error, porque a menudo el primero es el único relevante (como cuando el usuario olvida un campo obligatorio).
Estoy contando esos errores "únicos" y estoy haciendo un título H2 HTML usando pluralize y poniéndolo ANTES de la lista de errores.
Así que ahora, puedo usar el "devise_error_messages!" como el predeterminado y representa exactamente lo que ya estaba renderizando antes.
Si desea acceder a un mensaje de error específico en su vista, ahora le recomiendo usar directamente "resource.errors [: attribute] .first" o lo que sea.
Seya, Kulgar.