Rails 在 ajax 调用后不显示闪存消息



我正在编写一个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

并在我的应用程序中包含了以下闪存显示逻辑。haml

...
%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消息都不会显示。除了闪光消息之外,其他一切都如预期,我还没能弄清楚为什么

我怀疑这与我正在进行的AJAX刷新以及重定向(甚至可能是涡轮链接)有关,但我已经在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)

我想权衡一下,因为向头传递消息的需要似乎是Rails应该已经能够做到的一种全面的方法。

经过几个小时的搜索,我意识到我已经在做需要做的事情了,通过在我的控制器中传递以下行:

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

flash[:error]为以下视图设置了flash消息,responsd_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" %>

这个分部包含一个div,看起来如下:

<div id="flash_messages">
<% flash.each do |type, message| %>
<p><%= type %>: <%= message %></p>
<% end %>
</div>

最后,我创建了一个名为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视图,最后,用id="flash_messages"替换div内容的javascript被执行。我的原始视图更新了闪屏信息,世界一切正常。

注意:如果你使用Bootstrap或其他一些特殊的CSS框架,你可以在js.erb文件的$("#flash_messages").html(");调用中包含该代码

$("#flash_messages').html("<div class='alert <%= bootstrap_class_for(type) %> alert-dismissible' role='alert'><button class='close' data-dismiss='alert'>×</button><%= message.html_safe %></div>")

我知道这个问题是几个月前发布的,但当搜索这个确切的问题时,得到的回复似乎总是你需要通过标题发送快闪消息。我想证明还有另一种方法。希望这能帮助我未来的Rails新手们!

首先,感谢您提出全面的问题

这里有一个同样全面的答案:你如何处理Rail';Ajax请求的flash?


Ajax

我会认真研究一下你的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);
});

为协议的漏洞道歉,作为对@Celsian回答的评论,但我发现我对此缺乏声誉。。。

@Celsian,谢谢你,这很有帮助。然而,使用flash[:error]意味着闪存将在页面刷新后延迟。flash.now[:error] = "My flash message error."解决了这个问题。也涵盖了非AJAX的情况,我选择了:

respond_to do |format|
format.html { flash[:error] = "error"
redirect_to request.referrer }
format.js { flash.now[:error] = "error" }
end

这样,无论请求是否是AJAX,flash都会到达(并且不会受到欢迎)。

我还在你的引导程序增强代码行中发现了一个小错误:

$("#flash_messages')

应该是

$('#flash_messages')

最新更新