rails - 设计 - 处理 - devise_error_messages

AnA*_*ice 123 ruby-on-rails devise

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

<%= devise_error_messages! %>
Run Code Online (Sandbox Code Playgroud)

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

<% flash.each do |key, value| %>
    <div class="flash <%= key %>"><%= value %></div>
<% end %>
Run Code Online (Sandbox Code Playgroud)

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

谢谢.

Joh*_*ohn 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
Run Code Online (Sandbox Code Playgroud)

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

为了帮助您解决原始问题:这是devise_helper.rbGithub上的原始版本.看看如何遍历错误消息:

messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
Run Code Online (Sandbox Code Playgroud)

这应该可以帮助你开始.:)

另一个更新

resource对象实际上是设计使用的模型(go figure).

resource.class         #=> User
resource.errors.class  #=> ActiveModel::Error
Run Code Online (Sandbox Code Playgroud)

它似乎也被定义在更高的范围内(可能来自控制器),因此可以在各种地方访问它.

助手的任何地方

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
Run Code Online (Sandbox Code Playgroud)

你的观点

<div><%= resource.errors.inspect %></div>
Run Code Online (Sandbox Code Playgroud)


Luk*_*yka 35

以下解决方案适用于最新设计(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">&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 %>
Run Code Online (Sandbox Code Playgroud)

现在你有一些可回收的东西,你可以全面使用它.而不是标准设计:

<%= devise_error_messages! %>
Run Code Online (Sandbox Code Playgroud)

在表单中调用它,如下所示:

<%= render 'layouts/error_messages', object: resource %>
Run Code Online (Sandbox Code Playgroud)

你可以把它放在任何形式.您可以从表单传递变量,而不是传递设计资源:

<%= form_for @post do |f| %>
  <%= render 'layouts/error_messages', object: f.object %>  
  <%= f.text_field :content %>
  <%= f.submit %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

  • 酷解决方案.pluralize(object.errors.count,'errors'应该更改为pluralize(object.errors.count,'error'虽然 (2认同)

Eri*_* Hu 22

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

整个Devise你会看到有使用的电话render_with_scope.我相信这是一个由设计定义的方法,基本上将当前范围应用于下一个渲染视图.

为什么这有关系?Devise包含你的错误resource.errors(不是 @resource.errors).如果您想开箱即用,Devise可以正常工作.

如果您开始更改用户管理行为,则会出现这些错误的问题.通过添加一个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 %>
Run Code Online (Sandbox Code Playgroud)

# 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
Run Code Online (Sandbox Code Playgroud)

后一个代码块将Devise的错误消息作为一个数组并将其附加到flash[:notice](作为数组).每条消息将一次打印出一行.如果我有时间,我想我将改变Devise处理错误消息的方式,以便在我的应用程序中执行此操作,因为使用一个错误消息系统而不是两个错误消息系统似乎更清晰.

  • 非常感谢你,为了试图这样做,我正撞在墙上. (3认同)

Kul*_*gar 11

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

所以我找到了一种更简单的方法来获得"AnApprentice"想要的结果.

首先,如果您想在Devise插件中自定义任何内容,我强烈建议您复制"\ Ruby_repertory\lib\ruby​​\gems\1.9.1\gems\devise-version\app\controllers中的代码| helpers | mailers ..."到你想要的项目文件.

[编辑]或者你可以让你的文件继承"普通"设计文件......比如...说...你想只覆盖设计/ registrations_controller.rb中的一个函数,你的用户自定义的第一行注册控制器将是:

class Users::RegistrationsController < Devise::RegistrationsController
Run Code Online (Sandbox Code Playgroud)

[编辑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
Run Code Online (Sandbox Code Playgroud)

而且,在我看来,下一行的效果非常好:

<% devise_error_messages!.each do |key, value| %>
    <div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
Run Code Online (Sandbox Code Playgroud)

那么...然后您可以访问特定属性的错误,如下所示:

    #Imagine you want only the first error to show up for the login attribute:
    <%= devise_error_messages![:login].first %> 
Run Code Online (Sandbox Code Playgroud)

并且...每个属性只显示一个错误(第一个被捕获)的小技巧:

<% 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 %>
Run Code Online (Sandbox Code Playgroud)

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

大编辑:

由于我喜欢扩展我的代码,使其更清晰并与他人分享,我最近想改变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
Run Code Online (Sandbox Code Playgroud)

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

我正在计算那些"独特"错误,我正在使用复数制作一个H2 HTML标题并将其放在错误列表之前.

所以现在,我可以使用"devise_error_messages!" 作为默认值,它完全呈现我以前渲染的内容.

如果要在视图中访问特定的错误消息,我现在建议直接使用"resource.errors [:attribute] .first"或其他任何内容.

Seya,Kulgar.


Rya*_* Yu 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
Run Code Online (Sandbox Code Playgroud)

成功了!


Sco*_*ott 6

我在Rails 3中使用Devise,你的flash代码与我所拥有的完全相同.在我的应用程序中,代码按预期工作; 即,使用其余的flash消息输出Devise错误消息:

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

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


ddi*_*ier 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
Run Code Online (Sandbox Code Playgroud)

编辑:

对不起,我正在守卫,并且存在一些不受欢迎的行为.因为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
Run Code Online (Sandbox Code Playgroud)

views/shared/_messages.html.erb

<% devise_flash %>
<!-- then display your flash messages as before -->
Run Code Online (Sandbox Code Playgroud)