How do you handle Rail's flash with Ajax requests?
Solution 1:
You can also store the flash messages in the response headers using a after_filter block and display them using javascript:
class ApplicationController < ActionController::Base
after_filter :flash_to_headers
def 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 page
end
And in application.js add a global ajax handler. For jquery do something like this:
$(document).ajaxError(function(event, request) {
var msg = request.getResponseHeader('X-Message');
if (msg) alert(msg);
});
Replace alert() with your own javascript flash function or try jGrowl.
Solution 2:
And here is my version based on @emzero, with modifications to work with jQuery, tested on Rails 3.2
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
after_filter :flash_to_headers
def flash_to_headers
return unless request.xhr?
response.headers['X-Message'] = flash_message
response.headers["X-Message-Type"] = flash_type.to_s
flash.discard # don't want the flash to appear when you reload page
end
private
def flash_message
[:error, :warning, :notice].each do |type|
return flash[type] unless flash[type].blank?
end
end
def flash_type
[:error, :warning, :notice].each do |type|
return type unless flash[type].blank?
end
end
end
application.js
// FLASH NOTICE ANIMATION
var fade_flash = function() {
$("#flash_notice").delay(5000).fadeOut("slow");
$("#flash_alert").delay(5000).fadeOut("slow");
$("#flash_error").delay(5000).fadeOut("slow");
};
fade_flash();
var show_ajax_message = function(msg, type) {
$("#flash-message").html('<div id="flash_'+type+'">'+msg+'</div>');
fade_flash();
};
$(document).ajaxComplete(function(event, request) {
var msg = request.getResponseHeader('X-Message');
var type = request.getResponseHeader('X-Message-Type');
show_ajax_message(msg, type); //use whatever popup, notification or whatever plugin you want
});
layout: application.html.haml
#flash-message
- flash.each do |name, msg|
= content_tag :div, msg, :id => "flash_#{name}"
Solution 3:
This is needed in the js response
If you are using RSJ:
page.replace_html :notice, flash[:notice]
flash.discard
If you are using jQuery:
$("#flash_notice").html(<%=escape_javascript(flash.delete(:notice)) %>');
Solution 4:
I did it this way..
controller:
respond_to do |format| flash.now[:notice] = @msg / 'blah blah...' format.html format.js end
view:
<div id='notice'>
<%= render :partial => 'layouts/flash' , :locals => { :flash => flash } %>
</div>
layouts/_flash.html.erb
<% flash.each do |name, msg| %>
<div class="alert-message info">
<a class="close dismiss" href="#">x</a>
<p><%= msg %></p>
</div>
<% end %>
post.js.erb
$("#notice").html("<%= escape_javascript(render :partial => 'layouts/flash' , :locals => { :flash => flash }).html_safe %>");