我正在编写一个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 中包含以下闪存显示逻辑...
...
%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)
答案 0 :(得分:22)
我想要权衡一下,因为需要将消息传递给标题似乎是做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:
<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视图,最后,javascript用id =&#34替换我的div的内容; flash_messages&#34;被执行。我的原始视图已使用flash消息进行更新,所有内容都适用于全世界。
注意:如果你正在使用Bootstrap或其他一些特殊的CSS框架,你可以在js.erb文件中包含该代码&#39; s $(&#34;#flash_messages&#39;)。html(& #34;&#34;);呼叫。我按如下方式包含了我的Bootstrap代码:
$("#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>")
我知道这个问题是几个月前发布的,但是在搜索这个确切的问题时,响应似乎总是需要通过标头发送flash消息。我想表明还有另一种方法。希望这将有助于我的同伴Rails未来的新手!
答案 1 :(得分:9)
首先,感谢全面的问题
这是一个同样全面的答案:How do you handle Rail's flash with Ajax requests?
<强>的Ajax 强>
我会认真看看你的Ajax
刷新过程。刷新整个页面是非常低效的,我认为涉及更深层次的问题
为什么不尝试使用.js.erb
文件夹中的views
文件来直接通过该方法处理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);
});
答案 2 :(得分:0)
为协议的后遗症道歉,旨在作为对@Celsian 回答的评论,但我发现我缺乏声誉点......
@Celsian,谢谢,这很有帮助。
然而,使用 flash[:error]
意味着 Flash 会在页面刷新后停留。
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')