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