在我的用户编辑页面中,有一行如下:
<%= devise_error_messages! %>
问题是这不会以应用程序其余部分的标准方式输出错误:
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
我的问题是,如何让设计错误消息像使用flash.each的其他人一样工作?
感谢。
答案 0 :(得分:135)
我正在努力解决这个问题。我刚刚在Github上发现了这个问题https://github.com/plataformatec/devise/issues/issue/504/#comment_574788
Jose说devise_error_messsages!
方法只是一个存根(虽然它包含实现),我们应该覆盖/替换它。如果在wiki的某个地方指出这一点会很好,这就是为什么我猜有些像我们这样的人一直在猜测。
所以我将尝试重新打开模块并重新定义方法,从而有效地覆盖默认实现。我会告诉你它是怎么回事。
app/helpers/devise_helper.rb
并像这样覆盖了它:
module DeviseHelper
def devise_error_messages!
'KABOOM!'
end
end
知道这一点,我可以修改方法,以我想要的方式显示错误消息。
帮助您解决原始问题:这是原始devise_helper.rb
on Github。看看如何遍历错误消息:
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
这应该可以帮助你开始。 :)
resource
对象实际上是设计使用的模型(go figure)。
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>
答案 1 :(得分:32)
以下解决方案适用于最新设计(4.1.1)和Rails 4.2.6。但是很简单,我没有看到为什么它不会在10年后起作用的原因;)
如果你想回收你的错误消息并让它们在你的应用程序中看起来一样,我会推荐这样的东西(我和Michael Hartl tut学习的方式):
为错误消息创建部分内容:
layouts/_error_messages.html.erb
放入以下代码(这里我使用一些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 %>
现在你有一些可回收的东西,你可以全面使用它。 而不是标准设计:
<%= devise_error_messages! %>
在您的表单中调用它:
<%= render 'layouts/error_messages', object: resource %>
你可以把它放在任何形式。您可以从表单中传递变量,而不是传递设计资源:
<%= form_for @post do |f| %>
<%= render 'layouts/error_messages', object: f.object %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
答案 2 :(得分:23)
我知道这个问题发布已经有一段时间了,但我只是想对我发现的内容发表评论。已经回答的两个人对我很有帮助,我只是想做出贡献。
你会在整个Devise中看到有使用render_with_scope
的电话。我相信这是一个由设计定义的方法,基本上将当前范围应用于下一个渲染视图。
为什么这有关系?设计包含resource.errors
内的错误(不 @resource.errors
)。如果您想开箱即用,Devise可以正常工作,可以这么说。
如果您开始更改用户管理行为,则会出现这些错误的问题。通过在Devise以前没有的地方添加redirect_to
或render
(而不是render_with_scope
),您基本上会抛出错误消息。在我看来,这使得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处理错误消息的方式,以便在整个应用程序中执行此操作,因为使用一个错误消息系统而不是两个错误消息系统似乎更清晰。
答案 3 :(得分:11)
我只想在这里带一个新的小片:
所以我找到了一种更简单的方法来获得“AnApprentice”想要的结果。
首先,如果您想在Devise插件中自定义任何内容,我强烈建议您复制“\ Ruby_repertory \ lib \ ruby \ gems \ 1.9.1 \ gems \ devise-version \中的代码app \ controllers | helpers | mailers ...“到你想要的项目文件。
[编辑]或者你可以让你的文件继承自“普通”设计文件...就像...说...你想要只覆盖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”想要写的东西(为了更清洁的解决方案,请看下面的大编辑):
#/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 %>
并且......每个属性只显示一个错误(第一个被捕获)的小技巧:
<% 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_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属性,因为通常第一个是唯一相关的(比如当用户忘记一个必填字段时)。
我正在计算那些“独特”错误,我正在使用复数制作一个H2 HTML标题并将其放在错误列表之前。
所以现在,我可以使用“devise_error_messages!”作为默认值,它完全呈现我以前渲染的内容。
如果您想在视图中访问特定的错误消息,我现在建议直接使用“resource.errors [:attribute] .first”或其他任何内容。
塞牙, Kulgar。
答案 4 :(得分:11)
我通过创建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
工作!
答案 5 :(得分:6)
我在Rails 3中使用Devise,你的flash代码与我所拥有的完全相同。在我的应用程序中,代码按预期工作;即,使用其余的Flash消息输出设计错误消息:
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>
尝试这个确切的代码,看看它是否有所不同 - 不同的ID属性可能有所帮助。
答案 6 :(得分:5)
我走到了这一步,到目前为止一直在努力。 这会向闪存添加设计消息,因此可以照常使用。请考虑我是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
,因此它无法按预期工作。如果有人知道如何在动作之后但在渲染之前调用方法......
但你可以使用类似的东西:
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 -->
答案 7 :(得分:3)
如果您希望能够显示给定类型的多个闪存(:警告,:通知等等)并且不浪费时间尝试修改宝石行为,这是我使用的解决方案设计。我很确定它可以用于任何使用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.")
答案 8 :(得分:2)
我只是这样做,为我工作:在 app / helpers / 中,我创建了一个文件 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) %>
希望它能帮到你;)
答案 9 :(得分:2)
创建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
您认为
<%= devise_error_messages! %>
收件人:
<% devise_error_messages! %>
答案 10 :(得分:2)
非常简单的方法来显示每个字段的错误消息
<%= resource.errors.messages[:email].join(" ") %>
为每个字段添加字段名称,方括号位于您要显示内联错误消息的每一行的下方。
答案 11 :(得分:2)
如果您正在寻找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
答案 12 :(得分:2)
不可否认,有点hacky,但我正在使用这个助手(app / helpers / devise_helper.rb)来获取闪存并使用那些设置然后默认为resource.errors
。这只是基于设计库中的帮助程序。
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
答案 13 :(得分:1)
在上面使用所有If语句的地方添加Eric Hu的答案,而不是做这样的事情。
# 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 %>
答案 14 :(得分:1)
要显示控制器的设计错误,只显示第一个错误。
flash[:error] = @resource.errors.full_messages.first
答案 15 :(得分:0)
DeviseHelper#devise_error_messages!
已过时,将被
在下一个主要版本中删除。
Devise现在使用devise/shared/error_messages
下的局部显示
错误消息,使它们更易于自定义。
更新您的视图,更改来自以下位置的呼叫
<%= devise_error_messages! %>
收件人:
<%= render "devise/shared/error_messages", resource: resource %>
答案 16 :(得分:0)
对于materialisecss以toast形式显示设计错误消息,我在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 = ("<script>" + messages + "</script>").html_safe
end
end
我相信他们会以最干净的方式来写它,但它正在完美地完成
答案 17 :(得分:0)
简单,把下面的代码放在views/devise/sessions/new.html.erb
<% if flash[:alert] %>
<div class='alert alert-danger'><%= flash[:alert] %></div>
<% end %>
就是这样!
答案 18 :(得分:0)
我喜欢这样做,就像在其他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 %>
答案 19 :(得分:0)
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
答案 20 :(得分:-1)
我刚刚像约翰一样创建了一个app/helpers/devise_helper.rb
但是像这样覆盖了这个方法:
module DeviseHelper
def devise_error_messages!
flash[:error] = resource.errors.full_messages.join('<br />')
return ''
end
end
有了这个,我不需要修改任何其他内容。 这是个坏主意吗?我是铁道新手,请不要犹豫,纠正我。感谢。
答案 21 :(得分:-2)
我刚刚宣布了devise_error_messages!作为一个空帮手。 并手动获取和处理我的应用程序的一般_errors部分中的错误。看起来像最简单的解决方案,我不必遍历所有devise的文件并删除对错误处理程序的调用。