Ajax请求如何处理Rail的Flash?

我很满意我提出的解决scheme 。 基本上,我有一个辅助方法,重新加载Flash内联,然后我有一个after_filter清除闪光灯,如果请求是xhr。 有没有人有比这更简单的解决scheme?

更新:上面的解决scheme写回到Rails 1.x,不再支持。

您也可以使用after_filter块在响应头文件中存储Flash消息,并使用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 

在application.js中添加一个全局的ajax处理程序。 对于jquery做这样的事情:

 $(document).ajaxError(function(event, request) { var msg = request.getResponseHeader('X-Message'); if (msg) alert(msg); }); 

将alert()replace为您自己的JavaScript flash函数或尝试jGrowl。

这里是我的基于@emzero的版本,在jQuery上进行了修改,在Rails 3.2上进行了testing

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 }); 

布局:application.html.haml

  #flash-message - flash.each do |name, msg| = content_tag :div, msg, :id => "flash_#{name}" 

这在js响应中是需要的

如果您使用RSJ:

 page.replace_html :notice, flash[:notice] flash.discard 

如果你正在使用jQuery:

 $("#flash_notice").html(<%=escape_javascript(flash.delete(:notice)) %>'); 

我这样做了..

控制器

 respond_to do |format| flash.now[:notice] = @msg / 'blah blah...' format.html format.js end 

视图:

 <div id='notice'> <%= render :partial => 'layouts/flash' , :locals => { :flash => flash } %> </div> 

布局/ _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 %>"); 

build立在别人之上 –

(我们将完整的Flash对象作为JSON传递,使我们能够在浏览器中重build完整的Flash对象,这可以确保在Rails生成多个Flash消息的情况下显示所有的Flash消息。

 #application_controller.rb class ApplicationController < ActionController::Base after_filter :flash_to_headers def flash_to_headers if request.xhr? #avoiding XSS injections via flash flash_json = Hash[flash.map{|k,v| [k,ERB::Util.h(v)] }].to_json response.headers['X-Flash-Messages'] = flash_json flash.discard end end end 
 //application.js $(document).ajaxComplete(function(event, request){ var flash = $.parseJSON(request.getResponseHeader('X-Flash-Messages')); if(!flash) return; if(flash.notice) { /* code to display the 'notice' flash */ $('.flash.notice').html(flash.notice); } if(flash.error) { /* code to display the 'error' flash */ alert(flash.error); } //so forth } 

看起来像你需要的是flash.now[:notice] ,它只在当前操作中可用,而在下一个操作中不可用。 你可以看看这里的文档: http : //api.rubyonrails.com/classes/ActionController/Flash/FlashHash.html#M000327

像这样在控制器中分配消息:

  flash.now[:notice] = 'Your message' 

app / views / layouts / application.js.erb – Ajax请求的布局。 在这里你可以简单地使用

  <%= yield %> alert('<%= escape_javascript(flash.now[:notice]) %>'); 

或用一些丰富的animation使用gritter: http ://boedesign.com/demos/gritter/

  <%= yield %> <% if flash.now[:notice] %> $.gritter.add({ title: '--', text: '<%= escape_javascript(flash.now[:notice]) %>' }); <% end %> 

基于gudleik回答:

 class ApplicationController < ActionController::Base 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 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 

然后在你的application.js(如果你使用的是Rails的本地Prototype助手)添加:

 Ajax.Responders.register({ onComplete: function(event, request) { var msg = request.getResponseHeader('X-Message'); var type = request.getResponseHeader('X-Message-Type'); showAjaxMessage(msg, type); //use whatever popup, notification or whatever plugin you want } }); 

有一个叫做Unobtrusive Flash的gem,可以自动将flash消息编码成cookie。 在客户端的一个JavaScript检查闪光灯,并以任何你想要的方式显示它。 这正常和阿贾克斯请求无缝工作。

我修改了维克多S的答案,以解决一些情况下, flash[type].blank? 在评论中没有几个人所指出的那样工作。

 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, nil].each do |type| return "" if type.nil? return flash[type] unless flash[type].blank? end end def flash_type [:error, :warning, :notice, nil].each do |type| return "" if type.nil? return type unless flash[type].blank? end end 

然后rest是一样的

 // 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"); }; var show_ajax_message = function(msg, type) { $(".flash_message").html('<div class="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 }); 

这是我的版本(使用多重闪存通知和特殊字符UTF-8编码):

在ApplicationController中:

 after_filter :flash_to_headers def flash_to_headers return unless request.xhr? [:error, :warning, :notice].each do |type| if flash[type] response.headers["X-Ajax-#{type.to_s.humanize}"] = flash[type] end end flash.discard end 

在我的coffee-script(twitter bootstrap版本)里面:

 css_class = { Notice: 'success', Warning: 'warning', Error: 'error' } $(document).ajaxComplete (event, request) -> for type in ["Notice", "Warning", "Error"] msg = request.getResponseHeader("X-Ajax-#{type}") if msg? $('#notices').append("<div class=\"alert #{css_class[type]}\">#{decodeURIComponent(escape(msg))}</div>") 

另一种方法是更新/显示“notice”div与来自您的Ajax请求“OnFailure”处理程序的消息。 它使您能够以所需的效果显示这些Flash消息。 我用这个

  render:text =>“发生了一些错误”,:status => 444

在Javascript中

 新的AjaxRequest(...

   ,
    OnFailure:函数(transport){
       $( “#通知”),更新(transport.responseText);
      //显示消息  
    }

 );

HTH

我构build了一个包含一些行为的application_controller的引擎,在响应头中发送Flash消息,就像你们中的一些人所build议的那样。

https://github.com/bonzofenix/flajax

我能想到的唯一改进就是使page.reload_flash成为默认值(不必将其放在每个rjs文件中,如果不想重新加载flash,就像page.keep_flash那样将其显示出来。

我不知道从哪里开始,但知道一些铁轨我相信这并不难。

如果你想使用AJAX调用redirect_to不应该在控制器中使用。 相反,应该明确表示flash消息:

在your_controller中:

 respond_to :js def your_ajax_method flash[:notice] = 'Your message!' end 

在由your_ajax_method_in_the_controller命名的视图中

your_ajax_method_in_the_controller.js.haml

 :plain $("form[data-remote]") .on("ajax:success", function(e, data, status, xhr) { $('.messages').html("#{escape_javascript(render 'layouts/messages')}"); setTimeout(function(){ $(".alert").alert('close') }, 5000); }) 

请注意, 消息类是呈现消息的锚点。 这个类应该出现在你的视图或应用程序布局中。 如果使用ERB,则该行变为$('.messages').html("<%= j(render 'layouts/messages') %>");

embedded到HAML / ERB中的上述JavaScript是使用AJAX时显示Flash消息的关键。 对于非AJAX调用,所有其他组件保持不变。

您可以使用your_ajax_method_in_the_controller.js.coffee或普通的.js,但是那些railsvariables将不会被JS / Coffee所使用。 即使我在这里不使用variables,我更喜欢在HAML中包装JS来保持一致的代码库。

我利用Twitter Bootstrap进行样式化消息,因此$(".alert").alert('close')消除了通知。 这里是部分消息

布局/ _messages.html.haml

 - flash.each do |name, msg| - if msg.is_a?(String) .alert-messages %div{class: "alert alert-#{name == :notice ? "success" : "error"} fade in"} %a.close{"data-dismiss" => "alert"} %i.icon-remove-circle = content_tag :div, msg, id: "flash_#{name}" 

以防万一,警报的CSS在下面

 .alert-messages { position: fixed; top: 37px; left: 30%; right: 30%; z-index: 7000; }