Rails не отображает флэш-сообщения после вызова ajax
Я пишу приложение rails 4.0.2, и пытаюсь получить уведомление о Flash, которое будет отображаться в моем представлении после события AJAX.
На мой взгляд, я показываю календарь с днями, на которые пользователь может нажать. Когда они это делают, я запускаю событие AJAX через обработчик события onclick, который обновляет мою модель, добавляя или удаляя запись. После запуска события я завершаю обновление страницы, чтобы отображать обновленные результаты.
Я обнаружил, что мне нужно было обновить страницу во время события JS click, чтобы получить представление для правильного обновления. Недостаточно перенаправления или рендеринга в контроллере.
Итак, для этого я установил уведомление 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 не отображается. Все остальное работает как ожидалось, кроме флеш-сообщения, и я не смог понять, почему.
Я подозреваю, что это связано с обновлением 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)
Ответы
Ответ 1
Во-первых, спасибо за исчерпывающий вопрос
Вот такой же всесторонний ответ: Как вы справляетесь с флешкой Rail с запросами Ajax?
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 в вашем ответе
Это означает, что вам нужно будет что-то сделать, чтобы передать объект Flash через ваш запрос Ajax. И в соответствии с вопросом, который я разместил в верхней части этого ответа, вы можете использовать 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
Я хотел бы взвесить, поскольку необходимость передавать сообщения в заголовок представляла собой круглый способ сделать то, что Rails уже должно быть способным.
После нескольких часов поиска я понял, что уже делаю то, что нужно сделать, передав следующие строки в моем контроллере:
flash[:error] = "My flash message error."
respond_to do |format|
format.js
end
Вспышка [: ошибка] устанавливает сообщение Flash для следующего вида, response_to понимает, что у меня есть remote: true, установленный в моем link_to (исходный запрос ajax):
<%= link_to "My Ajax Request", some_path(@some_value), remote: true %>
и отвечает на ссылку как JavaScript. Вы можете включить format.html в этот блок, если вы все еще хотите иметь возможность вызывать тот же самый контроллер без удаленного набора в true.
В моем приложении application.html.erb у меня есть частичное, которое отображает флеш-сообщения:
<%= 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, выполняется действие контроллера, устанавливается флеш-сообщение, контроллер загружает представление js.erb и, наконец, javascript, чтобы заменить содержимое моего div id = "flash_messages" выполняется. Мое первоначальное представление обновляется флэш-сообщением, и все в порядке с миром.
Примечание. Если вы используете 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>")
Я знаю, что этот вопрос был опубликован несколько месяцев назад, но при поиске этой точной проблемы ответ всегда кажется, что вам нужно отправить флэш-сообщения через заголовки. Я хотел показать, что есть другой метод. Надеюсь, это поможет моим новичкам Rails в будущем!