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.
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.
Update
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. :)
Another update
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 just want to bring a new little piece here:
So I found an easier way to get the result that "AnApprentice" wanted.
First of all, if you want to customize anything within the Devise plug-in, I highly advise you to copy past the code from "\Ruby_repertory\lib\ruby\gems\1.9.1\gems\devise-version\app\controllers|helpers|mailers..." to the file you want in your project.
[Edit] Or you can make your file inherit from the "normal" devise files... Like... say... You want to overwrite only one function within the devise/registrations_controller.rb, the first line of your Users custom registrations controller would be:
class Users::RegistrationsController < Devise::RegistrationsController
[Edit August 7th 2013] Now Devise even provides a tool to generate controllers: https://github.com/plataformatec/devise/wiki/Tool:-Generate-and-customize-controllers
So... anyway... I managed to get what "AnApprentice" wanted just writing this (for a cleaner solution, see the following big edit) :
#/my_project/app/helpers/devise_helper.rb
module DeviseHelper
def devise_error_messages!
return "" if resource.errors.empty?
return resource.errors
end
end
And, in my view, the next lines worked pretty well:
<% devise_error_messages!.each do |key, value| %>
<div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
Well... then you can access to errors for a specific attribute like this:
#Imagine you want only the first error to show up for the login attribute:
<%= devise_error_messages![:login].first %>
And... A little trick to have only one error (the first to get catched) showing up per attribute:
<% 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 %>
I know it's been a while since this question was posted, but I think that it will help lot's of devise users :).
Big Edit:
As I love to extend my code, making it cleaner and share it with others, I recently wanted to change the devise_error_messages! method in order to use it in my views and make it display the trick I explained above.
So, here is my method:
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
No big deal here, I reused the code I wrote in my view to show only one error pey attribute, because often the first one is the only relevant (like when the user forgets one required field).
I'm counting those "unique" errors and I'm making a H2 HTML title using pluralize and putting it BEFORE the errors list.
So now, I can use the "devise_error_messages!" as the default one and it renders exactly what I was already rendering before.
If you want to access a specific error message in your view, I now recommend to use directly "resource.errors[:attribute].first" or whatever.
Seya,
Kulgar.
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!
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.
I came up to this and it's working so far.
That adds devise messages to the flash, so it can be used as usual. Please consider that I'm new to Ruby and 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
Edit:
Sorry I was running guard and some unwanted behavior was present. Since after_filter is called after the rendering so it doesn't work as expected. If someone know how to call a method after the action but before the rendering...
But you can use something like that instead:
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
In views/shared/_messages.html.erb
<% devise_flash %>
<!-- then display your flash messages as before -->
If you want to be able to display more than one flash of a given type (:alert, :notice, etc...) and not waste your time trying to modify a gem behavior, this is the solution I used with Devise. I'm pretty sure it could be used with any gem that uses flash messages.
First thing to do, in your application_controller.rb, add this:
# Adds the posibility to have more than one flash of a given type
def flash_message(type, text)
flash[type] ||= []
flash[type] << text
end
Second thing to do, displaying your flash messages with this in application.html.erb (or wherever you want):
<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>
Third thing to do, whenever you want to add a flash message in any controller, do this:
flash_message(:success, "The user XYZ has been created successfully.")
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! %>
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
If you are looking to piggyback off of devise_error_messages then you can so by adding to resource.errors
If you were to over ride the registration controller, it might look like
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
Very easy way to display error message for each field
<%= resource.errors.messages[:email].join(" ") %>
put for each field with field name in square bracket below every line where u want to display inline error message.
To show your devise error from your controller with only the first error to showing up.
flash[:error] = #resource.errors.full_messages.first
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 %>
i simply do this, worked for me: in app/helpers/, i create a file 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
in all view files i change
<%= devise_error_messages! %>
for:
<%= devise_error_messages_for(#your object in your formular)%>
for me it make in my view edit and new user:
<%=form_for resource, as: #user, url: user_path(#user),...
<%= devise_error_messages_for(#user) %>
hope it will help you ;)
DeviseHelper#devise_error_messages! is deprecated and will be
removed in the next major version.
Devise now uses a partial under devise/shared/error_messages to display
error messages by default, and make them easier to customize.
Update your views changing calls from:
<%= devise_error_messages! %>
to:
<%= render "devise/shared/error_messages", resource: resource %>
Remove the "devise_error_messages!" from "app/views/users/passwords/new" template.
Create custom controller for your user (app/controllers/users/passwords_controller.rb) and in an after filter add errors flash array:
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
I like to do it just like it's done in the other Devise controller with this cheat.
<% 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 %>
For materialisecss to display devise error messages as toast I added this code in 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
I am sure their would be cleanest way to write it but it's woking perfectly
Easy, place the following code in views/devise/sessions/new.html.erb
<% if flash[:alert] %>
<div class='alert alert-danger'><%= flash[:alert] %></div>
<% end %>
And that's it!
I just created an app/helpers/devise_helper.rb like John but overrode the method like that :
module DeviseHelper
def devise_error_messages!
flash[:error] = resource.errors.full_messages.join('<br />')
return ''
end
end
With this I don't have to modify anything else.
Is it a bad idea ? I'm new to rails, don't hesitate to correct me. Thanks.
I just declared devise_error_messages! as an empty helper.
And manually fetched and handled the errors in a general _errors partial for my application. Seemed like the simplest solution and I don't have to go through all of devise's files and remove the call to the error handler.
Related
I'm making rails + Devise + Bootstrap app.
Basically it seems like working well, but when it gets wrong password
, no error message is shown like this.
I can't figure out why it happened and how to fix it.
Could you give me any advise for that? Thanks in advance!
Add these lines above the yield block in your application layout as suggested in one comment.
# 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 %>
Just add this code in the controller action, where you want to show the error messages,
flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
This link gives you many answers for this
I'm using rails 4.2
I have a helper file called devise_helper.rb
module DeviseHelper
def devise_error_messages!
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 class="row">
<div class="large-12 columns">
<div data-alert class="alert-box alert radius">
<h4>#{sentence}</h4>
<ul>#{messages}</ul>
</div>
</div>
</div>
HTML
html.html_safe
end
end
to customize error messages and it's working for registrations and passwords pages, but not for sessions pages. Why is this? I know that I can add something like this:
<div class="row">
<% if notice %>
<div data-alert class="alert-box info radius">
<%= notice %><%= link_to "X", '#', :class => 'close' %>
</div>
<% end %>
<% if alert %>
<div data-alert class="alert-box alert radius">
<%= alert %><%= link_to "X", '#', :class => 'close' %>
</div>
<% end %>
</div>
To my application.html.erb file and error messages will display there, but I don't understand why I have to add that when I have the devise helper already.
For the passwords and registrations, I just had to add <%= devise_error_messages! %> but the sessions pages don't seem to work that way. I'm not sure if this is just how devise works or if there's something I'm missing.
EDIT:
I generated the sessions controller but I never changed anything in it since generating it. From what I understand, devise will just use its default controller until I change the one i generated. My passwords controller is like this as well. I did make some changes to the registrations controller to configure permitted parameters.
class Users::SessionsController < Devise::SessionsController
end
A login with blank/wrong fields does not trigger (your) validations on the model, and therefore won't show your validation errors !
if you debug with byebug (in the first line of your view for example), you'll notice
resource.errors.count # => 0
flash # => ....#flashes={"alert"=>"Invalid email or password."}
Devise populates the "alert flash" with specific sign in error messages unique to this context of sign-in.
Why do you not see all model validation error messages ? Because that wouldn't make sense : suppose your model has a mandatory :gender attribute with validates_presence_of :gender. If normal model errors were added, then you would also see "gender cannot be blank" in the list of errors when your user tries to sign in with a wrong login :oops:.
devise_error_messages! is a specific devise method meant to show those specific errors. You can think of it as a partial validation on the fields that are used for sign in (and that are defined in your devise config file)
WORKAROUND :
If you really want to show all your error messages, you could just explicitely run the validations :
at the beginning of devise_error_messages!
resource.validate # It will generate errors and populate `resource.errors`
I believe it shouldn't mess up with other actions that already work well (register, etc.)
For newer version of Rails/Devise I recommend:
Instead of <%= devise_error_messages! %> do:
<% if flash[:alert] %>
<%= flash[:alert] %>
<% end %>
Your test may look something like this (note, you must make this a 'feature' functional test to have access to the "page" variable):
RSpec.feature 'Sign In', :type => :feature do
describe "correct error message w/ wrong password" do
before :each do
#user = create(:user)
#user.confirm
visit new_user_session_path
fill_in "user_email", with: #user.email
fill_in "user_password", with: "wrongpassword"
click_button "Log in"
end
it "tells user on page 'Invalid Email or password'" do
expect(page).to have_text("Invalid Email or password")
end
end
end
When you ran devise:install (or something similar), it must have created views with some specific line of codes to display these messages.
If you look at this link, they explain that you can add <%= devise_error_messages! %> in your views to display those error messages (which isn't really different from having a generic <% flash.each {...} %> somewhere in your HTML...)
Most likely, the views related to sessions do not contain this line of code.
I like this way.
The HTML part is kind of original though.
I do not want to separate displaying error messages about authentication.
So, I'm using this way.
module DeviseHelper
def devise_error_messages!
flash_alerts = []
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]
sentence = I18n.t("devise.failure.invalid") #=> "Invalid email or password."
else
sentence = I18n.t("errors.messages.not_saved",
count: resource.errors.count,
resource: resource.class.model_name.human.downcase)
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
html = <<-HTML
<div class="alert alert-danger">
<div id="error_explanation">
<strong>#{sentence}</strong>
<ul class="m-b-0 p-l-30 ">#{messages}</ul>
</div>
</div>
HTML
html.html_safe
end
end
I have a form that has input fields that dont' map to a model object.
How can I add errors during a post that will show up int he view page?
I have done the below before on other pages:
if #users.errors.any? and then I loop through the errors.fullmessages.each on my other forms, but this time I can't really map to a particular model.
What options do I have?
You could take advantage of the flash hash, in which you could do the following:
Controller:
if #user.errors.any?
flash[:user_errors] = #user.errors
end
View:
<% if flash[:user_error] %>
# loop through errors
<% end %>
It's typical to use flash messages for that :
You can do a flash[:error] = 'Invalid Action' and then in your view :
<% if flash[:error] %>
<%=h flash[:error] %>
<% end %>
Im receiving this error in my Rails app and cant find the solution. I will add some code from the class where it fails. It might be a more of an architectural problem if you think so please do say and I will add more code from other classes. I basically only have this model, and one controller and another class which is located in lib. An then a view of course. Thanks in advance!
#app/models/news_api.rb
require 'open-uri'
class NewsApi
URL = "http://www.mysomething.com/partner/api/1_0/somerandomnumber/
channel/290/material/list/"
def self.download
new.document.css('news').map {|node| record(node) }
end
def document
Nokogiri::XML(open(URL))
puts URL.to_s
end
def record(node)
Story.new(node_to_hash(node))
end
def node_to_hash(node)
Hash[Story::ATTRIBUTES.collect {|attribute| [attribute, text(node, attribute)] }]
end
def text(node, selector)
node.css(selector).text
end
end
#idlefingers: Here is the code from my view. What Im doing is basically using Nokogiri to parse some xml from an API and then displaying the response in HTMl in my view.
<ul id="news">
<% #stories.each do |story| %>
<li class=" <%= story.type_of_media %>">
<h2><%= link_to story.header, story.url %></h2>
<p class="permalink"><%= link_to 'Trackback', story.url %></p>
<p class="meta">
<strong><%= story.source_name %></strong>
<br/>
<%= story.created_at %>
<br/>
<%= story.geo %>
</p>
<p class="summary"><%= story.summary %></p>
</li>
<% end %>
Where is the error coming from? At a glance, it looks like it's coming from the .document method, but it isn't clear. Can you add the error backtrace?
The .document method as it stands will be returning the result of puts URL.to_s, which will be nil. You just need to switch around the two lines in your .document method by the looks of it...
def document
puts URL.to_s
Nokogiri::XML(open(URL))
end
I was expecting a flash notice when authentication failures occurs in devise. But get nothing during a authentication failure, just the page refreshes and remains still.
I didn't change any stuffs. The default devise installation itself is not displaying flash errors with invalid authentication attempt. I just installed devise as a gem a tryed to uise it. Din't even change a word of the code that is generated.
May be I thought if is it due to some browser comparability issues.
But I get other mannually introduced flash messsages else working.
Any suggestions as to what may be broken.
I'm using rails 3.0.1
* Update *
I'm getting failure messages for user registration(sign up) but not for failures messages of signing in.
some googleing on this topic revealed that for sign up it expects:-
<%= devise_error_messages! %>
But for sign in it expects some other alert message tag to be referenced, but didn't get the exact info of what is that alert tag which i must use and wher to use ???
Please provide some suggestions !!!
Thanks in advance.
Atlast after some good amount of searching/browsing I found the answer,
you have to add the following piece of code in our application.html.erb file
<%- flash.each do |name, msg| -%>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<%- end -%>
After adding this I was able to see the sign_in failures alert messages :).
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
Rails 5.1, Devise 4.4.3
Inside of a form, errors can be displayed with:
<% resource.errors.full_messages.each do |msg| %>
<%= msg %>
<% end %>
I know this is old but I ended up here because I was having the same problem in rails 5.1 and the accepted answer didn't worked, so here's what I did. After overriding Devise::SessionController, add the following code to it:
after_action :unauthenticated
protected
def unauthenticated
flash[:alert] = t("devise.failure.#{request.env['warden'].message}") unless request.env['warden'].message.blank?
end
Also, on the same controller, copy and paste the code for the create method from your version of Devise, and remove the ! from warden.authenticate!. Because you removed the !, now you have to check if the resource is nil, and redirect if it is. In my case, the create method ended up like this:
def create
self.resource = warden.authenticate(auth_options)
redirect_to root_path and return if resource.nil?
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
Finally, you just have to print the flash messages on your views. I am using materialize, so I created a partial and added the following code to it (which you should customize to your own needs):
<% flash.each do |type, message| %>
<% if type == "notice" %>
<script id="toast">
$(function() {
Materialize.toast('<%= message %>', 4000);
});
</script>
<% elsif type == "success" %>
<script id="toast">
$(function() {
Materialize.toast('<%= message %>', 4000, 'green');
});
</script>
<% elsif type == "alert" %>
<script id="toast">
$(function() {
Materialize.toast('<%= message %>', 4000, 'orange');
});
</script>
<% end %>
<% end %>