rails - Devise - Handling - devise_error_messages

2020-01-23 10:05发布

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?

Thanks.

20条回答
一夜七次
2楼-- · 2020-01-23 10:55

Admittedly, a bit hacky, but I'm using this helper (app/helpers/devise_helper.rb) to grab flashes and use those if set then default to resource.errors. This is just based on the helper that's in the 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
查看更多
爷的心禁止访问
3楼-- · 2020-01-23 10:56

I solved this similarly to YoyoS, by creating an app/helpers/devise_helper.rb and placing this in it:

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!

查看更多
欢心
4楼-- · 2020-01-23 10:56

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:

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

查看更多
爷、活的狠高调
5楼-- · 2020-01-23 10:57

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

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

Create partial for error messages: layouts/_error_messages.html.erb Put inside following code (here I use some bootstrap 3 classes):

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

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 %>
查看更多
放荡不羁爱自由
6楼-- · 2020-01-23 10:59

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! %>
查看更多
beautiful°
7楼-- · 2020-01-23 10:59

Just to add to Eric Hu answer above where all the If statements are used, rather do something like this instead.

# 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 %>
查看更多
登录 后发表回答