【问题标题】:How do you handle Rail's flash with Ajax requests?您如何使用 Ajax 请求处理 Rail 的 flash?
【发布时间】:2015-07-02 06:18:08
【问题描述】:

我对我提出的the solution 非常满意。基本上,我有一个帮助方法来重新加载内联闪存,然后我有一个 after_filter,如果请求是 xhr,则清除闪存。有人有比这更简单的解决方案吗?

更新:上面的解决方案是在 Rails 1.x 中写回的,不再受支持。

【问题讨论】:

  • 我喜欢你的解决方案.. after_filter { flash.discard if request.xhr? }

标签: ruby-on-rails ajax


【解决方案1】:

您还可以使用 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);
});

用您自己的 javascript flash 函数替换 alert() 或尝试 jGrowl。

【讨论】:

  • 此外,您可以存储消息类型:response.headers['X-Message-Type'] = flash_type(而 flash_type 返回最重要的类型(错误 > 成功 > 通知)。另外,您可以使用ajaxComplete then 包含成功案例:$(document).ajaxComplete(function(e, request, opts) { fireFlash(request.getResponseHeader('X-Message'), request.getResponseHeader('X-Message-Type')); });
  • 如果您的 Rails 应用程序使用 Prototype 发出 ajax 请求,之前的 jquery 处理程序将无法工作。您需要使用相应的原型处理程序。见我上面的回答。
  • 为什么application.js顶部的cmets说不建议加代码?
【解决方案2】:

这是我基于 @emzero 的版本,经过修改后可与 jQuery 一起使用,在 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
});

布局:application.html.haml

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

【讨论】:

  • 这也适用于 rails 3.1.0。谢谢 Victor,为我开箱即用。
  • 很好的编译,虽然"$("#flash-message").ajaxComplete(function(event, request)" 不应该是"$(document)"?
  • 出于某种原因,'除非 flash[type].blank?'在某些情况下无法正常工作。没有闪烁的动作将呈现句子“错误、警告、通知”。我在 js 中通过使用“if (msg != "error, warning, notice") show_ajax_message(msg, type)' 来修补这个问题,但这显然是一个 hacky 解决方案。不过,我无法弄清楚问题的真正原因。
  • [:error, :warning, :notice].each {} 如果返回条件不满足则返回数组,所以这段代码需要稍作调整.. 但除此之外,很有帮助。
  • 如果重新编写代码以不返回字符串“错误、警告、通知”以及与 twitter-bootstrap gist.github.com/hbrandl/5253211一起玩得很好
【解决方案3】:

这是js响应中需要的

如果您使用的是 RSJ:

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

如果你使用的是 jQuery:

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

【讨论】:

  • 看起来在 Rails 3.1+ 中你需要使用flash.discard(:notice) 而不是flash.delete(:notice)
【解决方案4】:

我是这样做的..

控制器

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>        

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 %>");

【讨论】:

  • 在你的控制器中,我可以看到flash.now[:notice]= @msg / 'blah blah..' 的错字我也很好奇,你会把 post.js.erb 放在路径 app/assets/javascripts 中,不是吗?
  • post.js.erb 进入控制器的视图文件夹,在这种情况下是 "views/posts/post.js.erb" 。 msg / "blah blah" 我的意思是 msg 或一些随机消息,如 "blah blah"
【解决方案5】:

建立在他人之上 -

(我们将完整的 flash 对象作为 JSON 传递,使我们能够在浏览器中重构完整的 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
}

【讨论】:

  • 谢谢。我修改了 application.js 中的函数来喜欢这个 $.each( $.parseJSON(request.getResponseHeader('X-Flash-Messages')), function(key,value){ flash_message(key,value) }); 如果你有 js 函数来显示带有参数类型的 flash 和消息的 flash 消息
【解决方案6】:

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

【讨论】:

  • 嘿,我喜欢这个!没有其他人? :S
  • @le_Daf:使用flash.now 是解决不同问题的方法。 flash.now 的内容不会被 Ajax 回调神奇地插入到当前页面中。
  • 应该被称为 flash.eventually 而不是 flash.now ;)
【解决方案7】:

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

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

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

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

或使用 Gritter 制作一些丰富的动画:http://boedesign.com/demos/gritter/

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

【讨论】:

    【解决方案8】:

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

    【讨论】:

    • 你能解释一下return unless request.xhr吗?我的意思是在当前请求的末尾,如果我们添加了任何 flash 通知,我们将它们添加到响应标头中,然后在 js 中我们读取它们——很酷,但我不确定为什么我们有上述行
    【解决方案9】:

    有一个名为 Unobtrusive Flash 的 gem 可以自动将 flash 消息编码到 cookie 中。客户端的 javascript 检查闪存并以您想要的任何方式显示它。这在正常和 ajax 请求中都可以无缝工作。

    【讨论】:

    • 为我解决了所有问题。
    【解决方案10】:

    我修改了 Victor S 的答案,以修复一些 flash[type].blank? 不起作用的情况,正如 cmets 中很少有人指出的那样。

    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
    

    那么剩下的也一样

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

    【讨论】:

      【解决方案11】:

      这是我的版本(使用多个 Flash 通知和特殊字符 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
      

      在我的咖啡脚本中(推特引导版本):

      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>")
      

      【讨论】:

      • 它应该使用 utf8 解码的亚洲字符 ;-)
      • 不,不是!我查看了 RFC 文档,发现 http header 中只支持 ASCII 字符。
      【解决方案12】:

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

      渲染 :text => "发生了一些错误", :status => 444

      在 Javascript 中

      新的 AjaxRequest(... , OnFailure:功能(运输){ $("#notice").update(transport.responseText); // 显示消息 } );

      HTH

      【讨论】:

        【解决方案13】:

        我构建了一个引擎,其中包含一些对 application_controller 的行为,以便按照你们中的一些人的建议在响应标头中发送 flash 消息。

        https://github.com/bonzofenix/flajax

        【讨论】:

          【解决方案14】:

          我能想到的唯一改进是将 page.reload_flash 设为默认值(不必将其放在每个 rjs 文件中,并且如果您不想重新加载 flash 则使其显式,例如 page.keep_flash。

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

          【讨论】:

            【解决方案15】:

            如果您想使用 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);
                })
            

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

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

            您可以使用your_ajax_method_in_the_controller.js.coffee 或普通的.js,但这样rails 变量将无法用于JS/Coffee。尽管我在这里不使用变量,但我更喜欢将 JS 包装在 HAML 中以保持代码库的一致性。

            我利用 Twitter Bootstrap 来设置消息样式,因此 $(".alert").alert('close') 会淡化通知。这是 messages 部分:

            layouts/_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;
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-01-20
              • 2011-12-26
              • 2020-01-18
              • 1970-01-01
              • 2010-09-06
              • 1970-01-01
              • 2013-01-31
              • 2014-01-07
              相关资源
              最近更新 更多