通过 Ajax 实现 Rails 的闪存通知

31

简而言之,我有一个按钮。点击它后,我想要触发一个 Ajax 请求,获取 flash[:notice] 并将其显示在一个 div 中。

这是我的简短视图:

 <input type="button" id="search" value="display"/>

 <div id="notice">

 </div>

在视图中的我的 Ajax 请求:

$("#search").submit(function(){
                            $.ajax({
                                type: "POST",
                                url: //url to my show action
                                success: function(data){
                                      /*$("#notice").html("<%= flash[:notice] %>");
                                        $("#content").html(data);*/
                                }
                            });
                            return false;
                    });

我的控制器:

def HomeController <  ActionController::Base
  def index

  end

  def show
    respond_to do |format|
    format.js {  flash[:notice] = "" + count.to_s + " results found for " + params[:query][:search_key] + "" }
    end
    #render :partial => 'search'
  end
end

我的show.js.erb文件

#app/views/dashboard_home/show.js.erb
$("#notice").html("<%=j flash[:notice] %>");

$("#content").html("<%=j render partial: "search" %>");

问题是当我点击按钮时,通知正确显示。但相同的通知也会在下一次点击时继续存在。搜索部分包含表格,请帮忙!

2个回答

33

这里有一个例子,感谢Rich Peck的回答,我已经使其工作。我需要使用flash.now来确保闪现提示不会持久存在。

视图中的AJAX触发器:

<%= link_to "Email report", users_path, remote: true %>

控制器:

# app/controllers/users_controller
class UsersController < ApplicationController

  def index
    # do some things here

    respond_to do |format|
      format.js { flash.now[:notice] = "Here is my flash notice" }
    end
  end
end

渲染后的视图:

# app/views/users/index.js.erb
$("#flash").html('<%= j render partial: "shared/notice_banner" %>');

Flash提示信息在布局中的显示位置:

where the flash notice is displayed in the layout:

# app/views/layouts/application.html.erb
<div id="flash">
  <% if notice.present? %>
    <%= render partial: "shared/notice_banner" %>
  <% end %>
</div>


# app/views/shared/_notice_banner.html.erb
<div data-alert class="alert-box">
  <%= notice %>
  <a href="#" class="close">&times;</a>
</div>

25

会话

下次点击时仍会出现相同的通知

这是由于在Rails的session变量中存储的flash造成的:flash是会话的特殊部分,每个请求都会清除它。这意味着存储在其中的值只能在下一个请求中使用,这对于传递错误消息非常有用。

你遇到的问题是,我认为ajax不算作新请求(需要参考文献),因此数据将持续到下一次通过HTTP请求。

--

解决方法

我最初会尝试这样做:

def show
    respond_to do |format|
        format.js {  flash[:notice] = "my secret number "+rand(0,5)+" !" }
    end
end
您的主要问题在于,您正在使用ERB预处理器在JS中处理“flash”变量。这是一个问题,因为这意味着您将无法使用资产预编译来帮助其工作。
查看此问题后,为什么不尝试使用“after_filter”回调,如: after_filter 回调,正如此问题所述。
#app/controllers/home_controller.rb
Class Home < ActionController::Base
   after_filter { flash.discard if request.xhr? }, only: :show

    def show
        respond_to do |format|
            format.js {  flash[:notice] = "my secret number "+rand(0,5)+" !" }
        end
    end
end

--

更新

你应该在你的show.js.erb文件中包含success功能:

#app/views/home/show.js.erb
$("#notice").html("<%= flash[:notice] %>");
这意味着您可以从application.js中删除整个ajax调用,并将其替换为您的搜索表单中的remote: true
#app/views/search/index.html.erb
<%= form_tag home_show_path, remote: true %>
这能行的原因是,当你使用format.js响应块时,Rails会在视图中加载[action].js.erb文件。考虑到这仅发生在操作完成,所以它等同于ajax中的success函数。
通过这样做,您将能够从application.js中删除整个ajax函数,并用上面描述的UJS版本进行替换。

谢谢..但我应该如何在Ajax成功函数中访问Flash通知? - Santino 'Sonny' Corleone
你最好在views/home文件夹中创建show.js.erb文件 - 这将使用ERB预处理器加载该文件,从而允许你显示flash消息。由于这个文件是独立于asset pipeline的,所以在预编译资源时不会丢失 :) - Richard Peck
我应该把整个Ajax函数放在show.js.erb文件中吗? - Santino 'Sonny' Corleone
现在你唯一能期望的就是奇迹了! - Richard Peck
4
不要轻易放弃,告诉我发生了什么事情,我想解决这个问题。 - Richard Peck
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接