ajax调用后,Rails不显示flash消息

我正在编写一个rails 4.0.2应用程序,并且我试图在AJAX事件之后在我的视图中显示Flash通知。

在我看来,我会显示一个日历,其中包含用户可以点击的日期。 当他们这样做时,我通过onclick事件处理程序触发一个AJAX事件,该处理程序更新我的模型,添加或删除记录。 触发事件后,我完成页面刷新以显示更新的结果。

我发现在JS点击事件期间我必须刷新页面才能使视图正确更新。 仅在控制器中重定向或渲染是不够的。

所以,为此,我在控制器中设置了Flash通知…

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!' redirect_to manage_member_conflicts_path(@member) end 

…并在我的application.haml中包含以下flash显示逻辑…

 ... %body = p flash.inspect - flash.each do |type, message| = content_tag(:div, message, :class => "flash-#{type}") = render 'devise/menu/login_items' = yield 

注意:我在视图中使用HAML而不是ERB

然而,无论我尝试什么,Flash消息都不会显示。 除了 flash消息 之外 ,其他所有工作都按预期工作,我无法弄清楚原因

我怀疑它与AJAX刷新有关,我正在做的是重定向(甚至可能是turbolinks),但我在SO上看了其他答案,根本无法让它工作。 显然,我错过了一些东西。

这是JS点击处理程序(非常简单):

 window.calendarClick = (eventDate, linkURL) -> event = $(document.getElementById(eventDate)) event.toggleClass('selected') # Set or Remove conflicts $.ajax url: linkURL data: date: eventDate # Refresh the page $.ajax url: '', context: document.body, success: (s,x) -> $(this).html(s) 

首先,感谢综合问题

这是一个同样全面的答案: 如何使用Ajax请求处理Rail的闪存?


阿贾克斯

我认真看看你的Ajax刷新过程。 刷新整个页面是非常低效的,我认为涉及更深层次的问题

为什么不尝试在views文件夹中使用.js.erb文件,直接通过该方法处理JS:

 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 end end #app/views/controller/set_conflicts.js.erb $("#your_element").html(<%=j render manage_member_conflicts_path(@member) ) %>); 

响应

虽然我不确定这一点,但我知道Flash对象是由ActionDispatch :: Flash中间件处理的。 我认为XHR的处理方式与标准HTTP请求不同,因此无法在响应中显示Flash

这意味着你必须做一些事情来通过Ajax请求传递Flash对象。 根据我在本答案顶部发布的问题,您可以使用response headers执行此操作:

 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 $(document).ajaxError(function(event, request) { var msg = request.getResponseHeader('X-Message'); if (msg) alert(msg); }); 

我想权衡一下,因为需要将消息传递给头部,这似乎是做Rails应该已经能够做的事情的一种回合方式。

经过几个小时的搜索后,我意识到我已经通过在控制器中传递以下行来完成需要完成的工作:

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

flash [:error]为以下视图设置Flash消息,respond_to意识到我在我的link_to(原始ajax请求)中设置了remote:true:

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

并作为JavaScript响应链接。 如果您仍希望能够在没有远程设置为true的情况下调用相同的控制器,则可以在此块中包含format.html。

在我的application.html.erb中,我有一个部分呈现flash消息:

 <%= render "layouts/flash_notices" %> 

而partial包含一个如下所示的div:

 
<% flash.each do |type, message| %>

<%= type %>: <%= message %>

<% end %>

最后,我创建了一个名为MY_CONTROLLER_ACTION_NAME.js.erb的视图并插入:

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

现在,当我单击启用AJAX的链接时,执行控制器操作,设置flash消息,控制器加载js.erb视图,最后,执行j =以替换id =“flash_messages”的div的内容。 我的原始视图使用flash消息进行更新,所有内容都适用于全世界。

注意:如果您正在使用Bootstrap或其他一些特殊的CSS框架,您可以将该代码包含在js.erb文件的$(“#flash_messages”)。html(“”); call。我包含了我的Bootstrap代码,如下所示:

 $("#flash_messages').html("") 

我知道这个问题是几个月前发布的,但是在搜索这个确切的问题时,响应似乎总是需要通过标头发送flash消息。 我想表明还有另一种方法。 希望这将有助于我的同伴Rails未来的新手!