Ruby-on-rails rails - 设计 - 处理 - devise_error_messages
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4101641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
rails - Devise - Handling - devise_error_messages
提问by AnApprentice
in my user edit page, there is a line as follows:
在我的用户编辑页面中,有一行如下:
<%= devise_error_messages! %>
The problem is this does not output errors the standard way that the rest of the app does:
问题是这不会以应用程序其余部分的标准方式输出错误:
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
My question is, how do I get the devise error message to work like the others that use the flash.each?
我的问题是,如何让设计错误消息像使用 flash.each 的其他人一样工作?
Thanks.
谢谢。
回答by John
I'm trying to figure this out myself. I just found this issue logged on Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788
我正在尝试自己解决这个问题。我刚刚在 Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788上发现了这个问题
Jose is saying that devise_error_messsages!method is just a stub(though it contains implementation) and that we're supposed to override/replace it. It would have been nice if this was pointed out somewhere in the wiki, which is why i guess there are a few people like us that have been guessing.
Jose 是说该devise_error_messsages!方法只是一个存根(尽管它包含实现)并且我们应该覆盖/替换它。如果在 wiki 的某个地方指出这一点,那就太好了,这就是为什么我猜有一些像我们这样的人一直在猜测。
So I'm going to try reopening the module and redefine the method, effectively overriding the default implementation. I'll let you know how it goes.
所以我将尝试重新打开模块并重新定义方法,有效地覆盖默认实现。我会让你知道它是怎么回事。
Update
更新
Yep, that works. I created app/helpers/devise_helper.rband overrode it like so:
是的,这有效。我app/helpers/devise_helper.rb像这样创建并覆盖了它:
module DeviseHelper
def devise_error_messages!
'KABOOM!'
end
end
So knowing this, I can modify the method to display error messages the way I want it to.
所以知道了这一点,我可以修改方法以按照我想要的方式显示错误消息。
To help you solve your original problem: Here's the original devise_helper.rbon Github. Take a look at how the error messages are being traversed:
帮助您解决最初的问题:这是devise_helper.rbGithub上的原文。看一下错误消息是如何被遍历的:
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
That should help you get started. :)
这应该可以帮助您入门。:)
Another update
另一个更新
The resourceobject is actually the model that is being used by devise (go figure).
该resource对象实际上是正在使用由色器件(去图)模型。
resource.class #=> User
resource.errors.class #=> ActiveModel::Error
It also appears to be defined in a higher scope (probably coming from the controller), so it can be accessed in a variety of places.
它似乎也被定义在更高的范围内(可能来自控制器),因此可以在各种地方访问它。
Anywhere in your 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
Your View
你的看法
<div><%= resource.errors.inspect %></div>
回答by Lukasz Muzyka
Below solution works with latest devise as of now (4.1.1) and Rails 4.2.6. But is so simple that I don't see the reason why wouldn't it work 10 years from now;)
以下解决方案适用于目前的最新设计 (4.1.1) 和 Rails 4.2.6。但是太简单了,我不明白为什么它在 10 年后不起作用;)
If you want to recycle your error messages and have them look the same across your app I would recommend something like this (way I have learned with Michael Hartl tut):
如果你想回收你的错误消息并让它们在你的应用程序中看起来相同,我会推荐这样的东西(我从 Michael Hartl tut 那里学到的方式):
Create partial for error messages:
layouts/_error_messages.html.erbPut inside following code (here I use some bootstrap 3 classes):
为错误消息创建部分:
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">×</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 %>
Now you have something recyclable and you can use it across the board. Instead of standard devise:
现在你有了可回收的东西,你可以全面使用它。代替标准设计:
<%= devise_error_messages! %>
Call it in your form like this:
像这样以您的形式调用它:
<%= render 'layouts/error_messages', object: resource %>
You can put it in any form. Instead of passing devise resource you can pass variable from your form like this:
你可以把它放在任何形式。您可以像这样从表单中传递变量,而不是传递设计资源:
<%= form_for @post do |f| %>
<%= render 'layouts/error_messages', object: f.object %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
回答by Eric Hu
I know it's been a while since this question was posted, but I just wanted to comment on what I've found. The two people who've already answered have been a tremendous help to me and I just wanted to contribute.
我知道这个问题发布已经有一段时间了,但我只是想评论我的发现。已经回答的两个人对我有很大的帮助,我只是想做出贡献。
You'll see throughout Devise that there are calls using render_with_scope. I believe this is a method defined by devise and basically applies the current scope to the next view rendered.
你会在整个设计中看到有调用使用render_with_scope. 我相信这是一种由 devise 定义的方法,基本上将当前范围应用于渲染的下一个视图。
Why is this relevant? Devise contains your errors within resource.errors(not@resource.errors). Devise works fine if you want to use it out of the box, so to speak.
为什么这是相关的?设计包含resource.errors( not@resource.errors)内的错误。如果你想开箱即用,设计工作正常,可以这么说。
Problems with these errors arise if you start changing your user management behavior. By adding a redirect_toor render(instead of render_with_scope) where Devise previously didn't have one, you're basically tossing out the error messages. This makes Devise unfriendly to modification, in my opinion.
如果您开始更改用户管理行为,就会出现这些错误的问题。通过在 Devise 之前没有的地方添加redirect_toor render(而不是render_with_scope),您基本上是在丢弃错误消息。在我看来,这使得 Devise 对修改不友好。
My solution is this
我的解决方案是这样的
# 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 %>
and
和
# 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
The latter code block takes Devise's error messages as an array and appends it to flash[:notice](as an array). Each message will be printed out one line at a time. If I have the time, I think I'm going to change how Devise handles error messages to do this throughout my app, as it seems much cleaner to have one error message system instead of two.
后一个代码块将 Devise 的错误消息作为一个数组并将其附加到flash[:notice](作为一个数组)。每条消息将一次打印一行。如果我有时间,我想我将改变 Devise 处理错误消息的方式,以便在我的整个应用程序中执行此操作,因为拥有一个错误消息系统而不是两个错误消息系统似乎更清晰。
回答by Kulgar
I just want to bring a new little piece here:
我只想在这里带来一个新的小作品:
So I found an easier way to get the result that "AnApprentice" wanted.
所以我找到了一种更简单的方法来获得“AnApprentice”想要的结果。
First of all, if you want to customize anything within the Devise plug-in, I highly advise you to copy past the code from "\Ruby_repertory\lib\ruby\gems\1.9.1\gems\devise-version\app\controllers|helpers|mailers..." to the file you want in your project.
首先,如果您想自定义 Devise 插件中的任何内容,我强烈建议您将“\Ruby_repertory\lib\ruby\gems\1.9.1\gems\devise-version\app\controllers”中的代码复制过去|helpers|mailers...”添加到您的项目中所需的文件中。
[Edit] Or you can make your file inherit from the "normal" devise files... Like... say... You want to overwrite only one function within the devise/registrations_controller.rb, the first line of your Users custom registrations controller would be:
[编辑] 或者你可以让你的文件从“普通”设计文件继承......就像......说......你只想覆盖devise/registrations_controller.rb中的一个函数,你的用户自定义的第一行注册控制器将是:
class Users::RegistrationsController < Devise::RegistrationsController
[Edit August 7th 2013] Now Devise even provides a tool to generate controllers: https://github.com/plataformatec/devise/wiki/Tool:-Generate-and-customize-controllers
[Edit August 7th 2013] 现在 Devise 甚至提供了一个生成控制器的工具:https: //github.com/plataformatec/devise/wiki/Tool:-Generate-and-customize-controllers
So... anyway... I managed to get what "AnApprentice" wanted just writing this (for a cleaner solution, see the following big edit) :
所以......无论如何......我设法得到了“AnApprentice”想要的东西(为了更清晰的解决方案,请参阅以下大编辑):
#/my_project/app/helpers/devise_helper.rb
module DeviseHelper
def devise_error_messages!
return "" if resource.errors.empty?
return resource.errors
end
end
And, in my view, the next lines worked pretty well:
而且,在我看来,接下来的几行工作得很好:
<% devise_error_messages!.each do |key, value| %>
<div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
Well... then you can access to errors for a specific attribute like this:
嗯...然后您可以访问特定属性的错误,如下所示:
#Imagine you want only the first error to show up for the login attribute:
<%= devise_error_messages![:login].first %>
And... A little trick to have only one error (the first to get catched) showing up per attribute:
而且...一个小技巧,让每个属性只显示一个错误(第一个被捕获的错误):
<% 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 %>
I know it's been a while since this question was posted, but I think that it will help lot's of devise users :).
我知道这个问题发布已经有一段时间了,但我认为它会帮助很多设计用户:)。
Big Edit:
大编辑:
As I love to extend my code, making it cleaner and share it with others, I recently wanted to change the devise_error_messages! method in order to use it in my views and make it display the trick I explained above.
由于我喜欢扩展我的代码,使其更简洁并与他人分享,我最近想更改 devise_error_messages!方法以便在我的视图中使用它并使其显示我上面解释的技巧。
So, here is my method:
所以,这是我的方法:
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 big deal here, I reused the code I wrote in my view to show only one error pey attribute, because often the first one is the only relevant (like when the user forgets one required field).
这里没什么大不了的,我重用了我在视图中编写的代码来仅显示一个错误 pey 属性,因为通常第一个是唯一相关的(例如当用户忘记一个必填字段时)。
I'm counting those "unique" errors and I'm making a H2 HTML title using pluralize and putting it BEFORE the errors list.
我正在计算那些“独特的”错误,并使用复数形式制作 H2 HTML 标题并将其放在错误列表之前。
So now, I can use the "devise_error_messages!" as the default one and it renders exactly what I was already rendering before.
所以现在,我可以使用“devise_error_messages!” 作为默认值,它完全呈现我之前已经呈现的内容。
If you want to access a specific error message in your view, I now recommend to use directly "resource.errors[:attribute].first" or whatever.
如果您想访问视图中的特定错误消息,我现在建议直接使用“resource.errors[:attribute].first”或其他任何内容。
Seya, Kulgar.
塞亚,库尔加。
回答by r123454321
I solved this similarly to YoyoS, by creating an app/helpers/devise_helper.rband placing this in it:
我与 YoyoS 类似地解决了这个问题,方法是创建一个app/helpers/devise_helper.rb并将其放入其中:
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
Worked!
工作了!
回答by Scott
I'm using Devise in Rails 3 and your flash code is pretty much identical to what I've got. In my app, the code works as expected; i.e. Devise error messages are output with the rest of my flash messages:
我在 Rails 3 中使用 Devise,您的 Flash 代码与我所拥有的几乎相同。在我的应用程序中,代码按预期工作;即设计错误消息与我的其余 flash 消息一起输出:
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>
Try out this exact code and see if it makes any difference - the different ID attribute may help.
试试这个确切的代码,看看它是否有任何不同 - 不同的 ID 属性可能会有所帮助。
回答by ddidier
I came up to this and it's working so far. That adds devise messages to the flash, so it can be used as usual. Please consider that I'm new to Ruby and Rails...
我想到了这个,到目前为止它正在工作。这将向 flash 添加设计消息,因此它可以照常使用。请考虑我是 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
Edit:
编辑:
Sorry I was running guard and some unwanted behavior was present. Since after_filteris called after the rendering so it doesn't work as expected. If someone know how to call a method after the action but before the rendering...
抱歉,我正在守卫,并且出现了一些不需要的行为。因为after_filter在渲染之后被调用,所以它不能按预期工作。如果有人知道如何在操作之后但在渲染之前调用方法......
But you can use something like that instead:
但是你可以使用类似的东西:
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
在 views/shared/_messages.html.erb
<% devise_flash %>
<!-- then display your flash messages as before -->
回答by ddidier
If you want to be able to display more than one flash of a given type (:alert, :notice, etc...) and not waste your time trying to modify a gem behavior, this is the solution I used with Devise. I'm pretty sure it could be used with any gem that uses flash messages.
如果您希望能够显示多个给定类型的 flash(:alert、:notice 等...)并且不想浪费时间尝试修改 gem 行为,这就是我与 Devise 一起使用的解决方案。我很确定它可以与任何使用 flash 消息的 gem 一起使用。
First thing to do, in your application_controller.rb, add this:
首先要做的是,在您的 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
Second thing to do, displaying your flash messages with this in application.html.erb (or wherever you want):
第二件事,在 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>
Third thing to do, whenever you want to add a flash message in any controller, do this:
要做的第三件事,无论何时您想在任何控制器中添加一条 flash 消息,请执行以下操作:
flash_message(:success, "The user XYZ has been created successfully.")
回答by B-M
Create DeviseHelper:
创建设计助手:
module DeviseHelper
def devise_error_messages!
return "" if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg)}.join
return flash.now[:alert] = messages.html_safe
end
end
In your view, substitute
在你看来,替代
<%= devise_error_messages! %>
To:
到:
<% devise_error_messages! %>
回答by Douglas Drouillard
If you are looking to piggyback off of devise_error_messages then you can so by adding to resource.errors
如果您希望利用 devise_error_messages,那么您可以通过添加到 resource.errors 来实现
If you were to over ride the registration controller, it might look like
如果您要超越注册控制器,它可能看起来像
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

