繁体   English   中英

rails - 设计 - 处理 - devise_error_messages

[英]rails - Devise - Handling - devise_error_messages

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

<%= devise_error_messages! %>

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

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

我的问题是,如何让设计错误消息像使用 flash.each 的其他人一样工作?

谢谢。

我正在尝试自己解决这个问题。 我刚刚发现这个问题登录在 Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788

何塞说的是devise_error_messsages! 方法只是一个存根(尽管它包含实现),我们应该覆盖/替换它。 如果在维基的某个地方指出这一点会很好,这就是为什么我猜有一些像我们这样的人一直在猜测。

所以我将尝试重新打开模块并重新定义方法,有效地覆盖默认实现。 我会让你知道它是怎么回事。

更新

是的,这有效。 我创建了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对象实际上是设计正在使用的模型(见图)。

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>

以下解决方案适用于目前的最新设计 (4.1.1) 和 Rails 4.2.6。 但是太简单了,我不明白为什么它在 10 年后不起作用;)

如果你想回收你的错误消息并让它们在你的应用程序中看起来相同,我会推荐这样的东西(我从 Michael Hartl tut 那里学到的方式):

为错误消息创建部分: 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_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 %>

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

您将在整个设计中看到使用render_with_scope调用。 我相信这是一种由 devise 定义的方法,基本上将当前范围应用于渲染的下一个视图。

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

如果您开始更改用户管理行为,就会出现这些错误的问题。 通过在 Devise 之前没有的地方添加redirect_torender (而不是render_with_scope ),您基本上是在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 处理错误消息的方式,以便在我的整个应用程序中执行此操作,因为拥有一个错误消息系统而不是两个错误消息系统似乎要干净得多。

我通过创建一个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

工作了!

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

所以我找到了一种更简单的方法来获得“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

[Edit August 7th 2013] 现在 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”或其他任何内容。

塞亚,库尔加。

我在 Rails 3 中使用 Devise,您的 Flash 代码与我所拥有的几乎相同。 在我的应用程序中,代码按预期工作; 即设计错误消息与我的其余 flash 消息一起输出:

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

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

我想到了这个,到目前为止它正在工作。 这将向 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

编辑:

抱歉,我正在守卫,并且出现了一些不需要的行为。 由于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 -->

如果您希望能够显示多个给定类型的 flash(:alert、:notice 等...)并且不想浪费时间尝试修改 gem 行为,这就是我与 Devise 一起使用的解决方案。 我很确定它可以与任何使用 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.")

创建设计助手:

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

如果您希望利用 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 

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

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

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

诚然,有点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

我只是这样做,对我有用:在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) %>

希望它会帮助你;)

DeviseHelper#devise_error_messages! 已弃用,将在下一个主要版本中删除。

Devise 现在默认devise/shared/error_messages下的部分来显示错误消息,并使它们更易于定制。 更新您的视图更改调用:

      <%= devise_error_messages! %>

到:

      <%= render "devise/shared/error_messages", resource: resource %>

很简单,将以下代码放在 views/devise/sessions/new.html.erb 中

<% if flash[:alert] %>
 <div class='alert alert-danger'><%= flash[:alert] %></div>
<% end %>

就是这样!

从您的控制器显示您的设计错误,仅显示第一个错误。

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

只是在上面使用所有 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 %>
  1. 删除“devise_error_messages!” 来自“应用程序/视图/用户/密码/新”模板。
  2. 为您的用户创建自定义控制器 (app/controllers/users/passwords_controller.rb) 并在过滤器后添加错误闪存阵列:
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 %>

为了使 materialisecss 将设计错误消息显示为吐司,我在 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

我相信他们会是最干净的写法,但它完美地工作

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

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

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

我刚刚声明了 devise_error_messages! 作为空帮手。 并在我的应用程序的一般 _errors 部分中手动获取和处理错误。 似乎是最简单的解决方案,我不必浏览所有设计文件并删除对错误处理程序的调用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM