rails – devise – 处理 – devise_error_messages

在我的用户编辑页面中,有一行如下:

<%= devise_error_messages! %> 

问题是这不会输出错误的应用程序的其余部分的标准方式:

 <% flash.each do |key, value| %> <div class="flash <%= key %>"><%= value %></div> <% end %> 

我的问题是,我如何得到devise错误消息像其他使用flash.each一样工作?

谢谢。

我试图自己弄清楚这一点。 我刚刚发现这个问题loginGithub https://github.com/plataformatec/devise/issues/issue/504/#comment_574788

何塞说, devise_error_messsages! 方法只是一个存根 (尽pipe它包含实现),我们应该重写/replace它。 如果这个问题在维基的某个地方被指出的话,那将会很不错,所以我猜这里有一些人一直在猜测。

所以我会尝试重新打开模块并重新定义方法,有效地覆盖默认实现。 我会让你知道它是如何去的。

更新

是的,这是有效的。 我创build了app/helpers/devise_helper.rb并覆盖它,如下所示:

 module DeviseHelper def devise_error_messages! 'KABOOM!' end end 

所以知道这一点,我可以修改方法显示错误消息的方式,我想要的。

为了帮助你解决你原来的问题:这是Github上的原始devise_helper.rb 。 看看如何遍历错误消息:

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

这应该有助于你开始。 🙂

另一个更新

resource对象实际上是由devise使用的模型(去图)。

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

它也似乎被定义在一个更高的范围(可能来自控制器),所以它可以在各种地方访问。

在你的助手的任何地方

 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 

你的看法

 <div><%= resource.errors.inspect %></div> 

下面的解决scheme使用最新的devise(4.1.1)和Rails 4.2.6。 但是很简单,我不明白为什么10年后它不工作;)

如果你想回收你的错误信息,并让他们在你的应用程序看起来相同,我会推荐这样的事情(我已经与Michael Hartl tut了解到的):

创build部分错误消息: layouts/_error_messages.html.erb放在下面的代码(这里我使用一些引导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">&times;</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 %> 

现在你有可回收的东西,你可以全面使用它。 而不是标准的devise:

 <%= devise_error_messages! %> 

以这样的forms调用它:

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

你可以把它放在任何forms。 而不是传递devise资源,你可以像这样传递variables:

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

我知道这个问题发布之后已经有一段时间了,但是我只想评论我发现的内容。 已经回答的两个人对我有很大的帮助,我只是想贡献一下。

你会在整个devise中看到有使用render_with_scope调用。 我相信这是一个由devise定义的方法,基本上将当前范围应用到下一个呈现的视图。

为什么这是相关的? Devise在resource.errors不是 @resource.errors )中包含你的错误。 如果你想开箱使用它,devise工作正常,可以这么说。

如果您开始更改用户pipe理行为,则会出现这些错误的问题。 通过添加一个redirect_torender (而不是render_with_scope ),Devise以前没有一个,你基本抛出错误信息。 在我看来,这使得Devise对修改不友善。

我的解决办法是这样的

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

 # 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 

后面的代码块将Devise的错误消息作为数组添加到flash[:notice] (作为数组)。 每条消息将一次打印一行。 如果我有时间的话,我想我会改变devise处理错误消息的方式,以便在我的应用程序中执行此操作,因为看起来更清晰的是有一个错误消息系统,而不是两个错误消息系统。

我只想在这里带来一个新的小片:

所以我find了一个更简单的方法来得到“AnApprentice”想要的结果。

首先,如果您想在Devise插件中自定义任何内容,我强烈build议您复制代码从“\ Ruby_repertory \ lib \ ruby​​ \ gems \ 1.9.1 \ gems \ devise-version \ app \ controllers |助手|邮件…“到你想要在你的项目中的文件。

[编辑]或者你可以让你的文件inheritance“正常”的devise文件…就像…说…你只想覆盖devise/ registrations_controller.rb中的一个函数,你的用户自定义的第一行注册控制者将是:

 class Users::RegistrationsController < Devise::RegistrationsController 

[编辑2013年8月7日]现在Devise甚至提供了一个工具来生成控制器: https : //github.com/plataformatec/devise/wiki/Tool :-Generate-and-customize-controllers

所以…无论如何…我设法得到了什么“AnApprentice”只是写这个(一个更清洁的解决scheme,请参阅下面的大编辑):

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

而且,在我看来,接下来的工作很好:

 <% devise_error_messages!.each do |key, value| %> <div class="flash <%= key %>"><%= key %> <%= value %></div> <% end %> 

那么…那么你可以访问这样的特定属性的错误:

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

而且…一个小技巧只有一个错误(第一个得到catched)显示每个属性:

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

我知道这个问题已经发布了一段时间了,但是我认为它会帮助很多devise用户:)。

大编辑:

因为我喜欢扩展我的代码,使其更清洁并与其他人分享,所以我最近想要更改devise_error_messages! 方法,以便在我的视图中使用它,并使其显示我上面解释的技巧。

所以,这是我的方法:

  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 

这里没什么大不了的,我重复使用了我在视图中写的代码来显示一个错误pey属性,因为通常第一个是唯一相关的(比如当用户忘记一个必填字段时)。

我正在计算这些“唯一”的错误,我正在使用复数formsH2的HTML标题,并把它放在错误列表之前。

所以现在,我可以使用“devise_error_messages!” 作为默认的一个,它呈现了我以前已经呈现的东西。

如果你想在你的视图中访问特定的错误信息,我现在build议直接使用“resource.errors [:attribute] .first”或其他。

Seya,Kulgar。

我通过创build一个app/helpers/devise_helper.rb并将其放置到YoyoS中来解决这个问题:

 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 

成功了!

我在Rails 3中使用Devise,你的flash代码和我的代码非常相似。 在我的应用程序中,代码按预期工作; 即devise错误消息与我的其他消息一起输出:

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

试试这个确切的代码,看看它是否有任何区别 – 不同的ID属性可能有所帮助。

我想到了这一点,它的工作到目前为止。 这增加了devise消息到闪存,所以它可以像往常一样使用。 请考虑我是Ruby和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 

编辑:

对不起,我正在跑卫,一些不想要的行为出现了。 由于after_filter在渲染after_filter调用,所以它不能按预期工作。 如果有人知道如何在动作之后但渲染之前调用方法

但是你可以使用类似的东西:

 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 

views/shared/_messages.html.erb

 <% devise_flash %> <!-- then display your flash messages as before --> 

如果您希望能够显示给定types(:alert,:notice等等)的多个闪光灯,而不是浪费您的时间尝试修改gem行为,那么这是我与Devise一起使用的解决scheme。 我很确定它可以用于任何使用flash消息的gem。

首先要做的,在你的application_controller.rb中添加:

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

第二件事,在application.html.erb(或任何你想要的)中用这个来显示你的flash消息:

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

第三件事,只要你想在任何控制器中添加一个flash消息,就这样做:

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

诚然,有点hacky,但我使用这个助手(app / helpers / devise_helper.rb)抢闪烁,并使用这些如果设置,则默认为resource.errors 。 这只是基于devise 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 

非常简单的方法来显示每个字段的错误消息

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

将字段名称的每个字段放在要显示内联错误消息的每一行下面的方括号中。

我只是这样做,为我工作:在应用程序/助手/ ,我创build一个文件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 

在所有视图文件我改变

 <%= devise_error_messages! %> 

对于:

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

对我来说,它使我认为编辑和新用户:

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

希望它能帮助你;)

要显示您的控制器错误,只显示第一个错误。

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

如果你正在寻找devise_error_messages,那么你可以通过添加resource.errors

如果您要过度使用注册控制器,可能看起来像

 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 

只要在上面Eric Hu的回答中添加所有If语句,而不是像这样做。

 # 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. 删除“devise_error_messages!” 从“应用程序/视图/用户/密码/新”模板。
  2. 为你的用户(app / controllers / users / passwords_controller.rb)创build自定义控制器,并在后面的filter添加错误闪存arrays:
 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 

我喜欢这样做,就像它在另一个Devise控制器做这个作弊。

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

我刚刚创build了一个像John一样的app/helpers/devise_helper.rb但是覆盖了这个方法:

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

有了这个,我不需要修改任何东西。 这是一个坏主意吗? 我是新手,不要犹豫,纠正我。 谢谢。

我刚刚宣布devise_error_messages! 作为一个空的帮手。 并手动提取和处理在我的应用程序的一般的_errors部分错误。 看起来像最简单的解决scheme,我不必通过devise的所有文件,并删除对error handling程序的调用。