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