javascript Rails 在 ajax 调用后不显示 Flash 消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21032465/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails doesn't display flash messages after ajax call
提问by Donovan
I'm writing a rails 4.0.2 app, and am trying to get a Flash notice to display in my view after an AJAX event.
我正在编写一个 rails 4.0.2 应用程序,并试图在 AJAX 事件之后让 Flash 通知显示在我的视图中。
In my view I display a calendar with days a user can click on. When they do so, I fire an AJAX event via an onclick event handler which updates my model, either adding or removing a record. After firing the event, I complete a page refresh in order to display the updated results.
在我看来,我显示了一个日历,其中包含用户可以点击的天数。当他们这样做时,我通过 onclick 事件处理程序触发 AJAX 事件,该事件处理程序更新我的模型,添加或删除记录。触发事件后,我完成页面刷新以显示更新的结果。
I found I had to do a page refresh during the JS click event in order to get the view to update properly. A redirect or render in the controller alone wasn't enough.
我发现我必须在 JS 单击事件期间刷新页面才能正确更新视图。仅在控制器中重定向或呈现是不够的。
So, to that effect, I have set a Flash notice in my controller...
所以,为此,我在我的控制器中设置了一个 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
... and have included the following flash display logic in my application.haml...
...并在我的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
Note: I use HAML instead of ERB in my views
注意:我在视图中使用 HAML 而不是 ERB
Yet, no matter what I try, the Flash message does not display. Everything else works as expected exceptthe flash message, and I haven't been able to figure out why.
然而,无论我尝试什么,Flash 消息都不会显示。除了flash 消息外,其他一切都按预期工作,我一直无法弄清楚原因。
I suspect it's got something to do with the AJAX refresh I'm doing combined with the redirect (and maybe even turbolinks) but I've looked through other answers here on SO and simply can't get it to work. Clearly, I'm missing something.
我怀疑这与我正在结合重定向(甚至可能是 turbolinks)进行的 AJAX 刷新有关,但我已经在 SO 上查看了其他答案,但根本无法使其正常工作。显然,我错过了一些东西。
Here's the JS click handler (it's pretty simple):
这是 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)
采纳答案by Richard Peck
Firstly, thanks for comprehensive question
首先,感谢全面的问题
Here is an equally comprehensive answer: How do you handle Rail's flash with Ajax requests?
这是一个同样全面的答案:您如何处理带有 Ajax 请求的 Rail 闪存?
Ajax
阿贾克斯
I'd seriously look at your Ajax
refresh process. Refreshing the whole page is super inefficient, and I think covering a deeper issue
我会认真查看您的Ajax
刷新过程。刷新整个页面非常低效,我认为涵盖了更深层次的问题
Why don't you try using a .js.erb
file in the views
folder, to handle JS directly by the method:
不如试试用.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) ) %>);
Response
回复
Although I don't know this for sure, I know the Flash objects are handled by ActionDispatch::Flashmiddleware. I believe this is not handled for XHR in the same way as standard HTTP requests, consequently preventing Flash from being shown in your response
虽然我不确定这一点,但我知道 Flash 对象是由ActionDispatch::Flash中间件处理的。我相信 XHR 的处理方式与标准 HTTP 请求的处理方式不同,因此会阻止 Flash 显示在您的响应中
This means you'll have to do something to pass the Flash object through your Ajax request. And according to the question I posted at the top of this answer, you can use the response headers
to do it:
这意味着您必须做一些事情才能通过 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);
});
回答by Celsian
I'd like to weigh in as the need to pass messages to the header seemed like a round-a-bout way of doing something Rails should already be capable of.
我想权衡一下,因为需要将消息传递到标头似乎是做一些 Rails 应该已经能够做到的事情的循环方式。
After several hours of searching I realized I was already doing what needed to be done by passing the following lines in my controller:
经过几个小时的搜索,我意识到我已经在通过在我的控制器中传递以下几行来做需要做的事情:
flash[:error] = "My flash message error."
respond_to do |format|
format.js
end
The flash[:error] sets the Flash message for the following view, the respond_to realizes that I have remote: true set in my link_to (original ajax request):
flash[:error] 为以下视图设置 Flash 消息,respond_to 意识到我在我的 link_to 中设置了 remote: true (原始 ajax 请求):
<%= link_to "My Ajax Request", some_path(@some_value), remote: true %>
and responds to the link as JavaScript. You can include format.html in this block if you still want to have the ability to call that same controller without remote set to true.
并作为 JavaScript 响应链接。如果您仍然希望能够在不将 remote 设置为 true 的情况下调用相同的控制器,则可以在此块中包含 format.html。
In my application.html.erb I have a partial that renders flash messages:
在我的 application.html.erb 中,我有一个呈现 Flash 消息的部分:
<%= render "layouts/flash_notices" %>
and that partial contains a div that looks like the following:
并且该部分包含一个如下所示的 div:
<div id="flash_messages">
<% flash.each do |type, message| %>
<p><%= type %>: <%= message %></p>
<% end %>
</div>
Finally I created a view called MY_CONTROLLER_ACTION_NAME.js.erb and inserted:
最后我创建了一个名为 MY_CONTROLLER_ACTION_NAME.js.erb 的视图并插入:
<% flash.each do |type, message| %>
$("#flash_messages").html("<%= type.to_s.humanize %>: <%= message.html_safe %>")
<% end %>
Now when I click my AJAX enabled link, the controller action is executed, the flash message is set, the controller loads the js.erb view and finally, the javascript to replace the contents of my div with id="flash_messages" is executed. My original view is updated with the flash message and all is right with the world.
现在,当我单击启用 AJAX 的链接时,将执行控制器操作,设置 flash 消息,控制器加载 js.erb 视图,最后执行用 id="flash_messages" 替换 div 内容的 javascript。我的原始视图已使用 Flash 消息更新,世界一切正常。
Note: If you're using Bootstrap or some other special CSS framework you can include that code in the js.erb file's $("#flash_messages').html(" "); call. I included my Bootstrap code as follows:
注意:如果您使用 Bootstrap 或其他一些特殊的 CSS 框架,您可以将该代码包含在 js.erb 文件的 $("#flash_messages').html(" "); 调用中。我包含我的 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>")
I know this question was posted several months ago, but when searching for this exact issue the response always seems to be that you need to send the flash messages via the headers. I wanted to show there is another method. Hopefully this will help my fellow Rails newbies of the future!
我知道这个问题是几个月前发布的,但是在搜索这个确切的问题时,响应似乎总是您需要通过标题发送 Flash 消息。我想展示另一种方法。希望这对我未来的 Rails 新手有所帮助!