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
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.
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.
Yep, that works. I created app/helpers/devise_helper.rb
and overrode it like so:
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.rb
on Github. Take a look at how the error messages are being traversed:
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
That should help you get started. :)
The resource
object is actually the model that is being used by devise (go figure).
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>
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">×</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 %>
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.
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.
Problems with these errors arise if you start changing your user management behavior. By adding a redirect_to
or 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.
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.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With