Rails doesn't display flash messages after ajax call Rails doesn't display flash messages after ajax call ajax ajax

Rails doesn't display flash messages after ajax call


I'd like to weigh in as the need to pass messages to the header seemed like a round-a-bout way of doing something Rails should already be capable of.

After several hours of searching I realized I was already doing what needed to be done by passing the following lines in my controller:

flash[:error] = "My flash message error."respond_to do |format|  format.js end

The flash[:error] sets the Flash message for the following view, the respond_to realizes that I have remote: true set in my link_to (original ajax request):

<%= link_to "My Ajax Request", some_path(@some_value), remote: true %>

and responds to the link as JavaScript. You can include format.html in this block if you still want to have the ability to call that same controller without remote set to true.

In my application.html.erb I have a partial that renders flash messages:

<%= render "layouts/flash_notices" %>

and that partial contains a div that looks like the following:

<div id="flash_messages">  <% flash.each do |type, message| %>    <p><%= type %>: <%= message %></p>  <% end %></div>

Finally I created a view called MY_CONTROLLER_ACTION_NAME.js.erb and inserted:

<% flash.each do |type, message| %>  $("#flash_messages").html("<%= type.to_s.humanize %>: <%= message.html_safe %>")<% end %>

Now when I click my AJAX enabled link, the controller action is executed, the flash message is set, the controller loads the js.erb view and finally, the javascript to replace the contents of my div with id="flash_messages" is executed. My original view is updated with the flash message and all is right with the world.

Note: If you're using Bootstrap or some other special CSS framework you can include that code in the js.erb file's $("#flash_messages').html(" "); call. I included my Bootstrap code as follows:

$("#flash_messages').html("<div class='alert <%= bootstrap_class_for(type) %> alert-dismissible' role='alert'><button class='close' data-dismiss='alert'>×</button><%= message.html_safe %></div>")

I know this question was posted several months ago, but when searching for this exact issue the response always seems to be that you need to send the flash messages via the headers. I wanted to show there is another method. Hopefully this will help my fellow Rails newbies of the future!


Firstly, thanks for comprehensive question

Here is an equally comprehensive answer: How do you handle Rail's flash with Ajax requests?


Ajax

I'd seriously look at your Ajax refresh process. Refreshing the whole page is super inefficient, and I think covering a deeper issue

Why don't you try using a .js.erb file in the views folder, to handle JS directly by the method:

def set_conflicts  @conflict = @member.conflicts.for_date(params[:date]).first  if @conflict    @conflict.destroy  else    conflict_date = Date.parse(params[:date])    unless Conflict.create(        month: conflict_date.month,        day:   conflict_date.day,        year:  conflict_date.year,        member: @member    )      flash[:alert] = 'Oops, there was a problem updating conflicts'    end  end  flash[:notice] = 'This is a test!'  respond_to do |format|      format.html { redirect_to manage_member_conflicts_path(@member) }      format.js   endend#app/views/controller/set_conflicts.js.erb$("#your_element").html(<%=j render manage_member_conflicts_path(@member) ) %>);

Response

Although I don't know this for sure, I know the Flash objects are handled by ActionDispatch::Flash middleware. I believe this is not handled for XHR in the same way as standard HTTP requests, consequently preventing Flash from being shown in your response

This means you'll have to do something to pass the Flash object through your Ajax request. And according to the question I posted at the top of this answer, you can use the response headers to do it:

class ApplicationController < ActionController::Baseafter_filter :flash_to_headersdef flash_to_headers  return unless request.xhr?  response.headers['X-Message'] = flash[:error]  unless flash[:error].blank?  # repeat for other flash types...  flash.discard  # don't want the flash to appear when you reload pageend$(document).ajaxError(function(event, request) {  var msg = request.getResponseHeader('X-Message');  if (msg) alert(msg);});


Apologies for the breech of protocol, intended as a comment to @Celsian’s answer but I found I lack reputation points for that...

@Celsian, thank you this was very helpful.Using flash[:error] however means the flash will linger after a page refresh.flash.now[:error] = "My flash message error." resolves this.Covering the non-AJAX situation also, I went with:

  respond_to do |format|     format.html { flash[:error] = "error"                   redirect_to request.referrer }     format.js { flash.now[:error] = "error" }   end

this way, the flash arrives (and doesn’t outstay its welcome) whether the request is AJAX or not.

I also spotted a small typo in your bootstrap-enhanced line of code:

$("#flash_messages')

should be

$('#flash_messages')