Как вы справляетесь с Flash Rail с Ajax-запросами?

Я очень доволен решением, которое я придумала. По сути, у меня есть вспомогательный метод, который перезагружает флэш-память, а затем у меня есть after_filter, который очищает флэш-память, если запрос xhr. У кого-нибудь есть более простое решение, чем это?

Обновление: Решение выше было записано в Rails 1.x и больше не поддерживается.

14.12.2008 08:40:04
Мне нравится ваше решение ..after_filter { flash.discard if request.xhr? }
Peter Ehrlich 22.10.2012 23:30:45
15 ОТВЕТОВ

Единственное улучшение, о котором я могу подумать, - это сделать по умолчанию page.reload_flash (не нужно помещать его в каждый файл rjs, и сделать его недействительным, если вы не хотите перезагружать flash, что-то вроде page.keep_flash.

Я не знаю, с чего начать, но зная некоторые рельсы, я уверен, что это не так сложно.

0
15.12.2008 11:24:36

Похоже, вам нужно то flash.now[:notice], что доступно только в текущем действии, а не в следующем. Вы можете посмотреть документацию здесь: http://api.rubyonrails.com/classes/ActionController/Flash/FlashHash.html#M000327

6
1.01.2009 18:51:45
Эй, мне это нравится! Никто другой ? : S
Bachet 22.04.2012 18:22:39
@le_Daf: Использование flash.now- это решение другой проблемы. Содержимое flash.nowне волшебным образом вставляется в текущую страницу с помощью обратного вызова Ajax.
Confusion 20.07.2012 06:49:42
Должно было называться flash.eventually вместо flash.now;)
Deborah 13.12.2013 05:58:53

Это необходимо в ответе JS

Если вы используете RSJ:

page.replace_html :notice, flash[:notice]
flash.discard

Если вы используете jQuery:

$("#flash_notice").html(<%=escape_javascript(flash.delete(:notice)) %>');
15
8.01.2009 11:28:14
Похоже, что в Rails 3.1+ вам нужно использовать, flash.discard(:notice)а неflash.delete(:notice)
Adrian Macneil 28.08.2012 05:08:34

Другим способом было бы обновить / отобразить div «note» с сообщением от вашего обработчика Ajax-запросов «OnFailure». Это дает вам возможность показывать эти флэш-сообщения с требуемым эффектом. Я использовал это

 render: text => "Произошла какая-то ошибка",: status => 444

в JavaScript

 новый AjaxRequest (...

  ,
   OnFailure: функция (транспортная) {
      $ ( "# Извещение") обновление (transport.responseText).
     // показать сообщение  
   }

);

НТН

1
11.03.2009 12:38:22

Вы также можете хранить флэш-сообщения в заголовках ответов, используя блок after_filter, и отображать их, используя javascript:

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

А в application.js добавьте глобальный обработчик ajax. Для jquery сделайте что-то вроде этого:

$(document).ajaxError(function(event, request) {
  var msg = request.getResponseHeader('X-Message');
  if (msg) alert(msg);
});

Замените alert () на свою собственную функцию flash javascript или попробуйте jGrowl.

63
28.03.2013 10:54:39
Кроме того, вы можете сохранить тип сообщения: response.headers['X-Message-Type'] = flash_type(тогда как flash_type возвращает наиболее важный тип (ошибка> успех> уведомление). Кроме того, вы можете использовать его ajaxCompleteдля включения случаев успеха:$(document).ajaxComplete(function(e, request, opts) { fireFlash(request.getResponseHeader('X-Message'), request.getResponseHeader('X-Message-Type')); });
crispy 20.12.2010 17:00:12
Если ваше приложение rails использует Prototype для выполнения ajax-запроса, предыдущий обработчик jquery не будет работать. Вам нужно будет использовать соответствующие обработчики прототипов. Смотрите мой ответ выше.
emzero 15.02.2011 18:05:27
почему в комментариях вверху application.js говорится, что не стоит добавлять туда код?
Steve 24.02.2012 09:33:38

На основании гудлейка ответ:

class ApplicationController < ActionController::Base
  after_filter :flash_to_headers

def flash_to_headers
  return unless request.xhr?
  response.headers['X-Message'] = flash_message
  response.headers["X-Message-Type"] = flash_type

  flash.discard # don't want the flash to appear when you reload page
end

private

def flash_message
  [:error, :warning, :notice].each do |type|
    return flash[type] unless flash[type].blank?
  end
end

def flash_type
  [:error, :warning, :notice].each do |type|
    return type unless flash[type].blank?
  end
end

Затем в вашем application.js (если вы используете встроенные помощники Prototype в Rails) добавьте:

Ajax.Responders.register({
onComplete: function(event, request) {
   var msg = request.getResponseHeader('X-Message');
   var type = request.getResponseHeader('X-Message-Type');
   showAjaxMessage(msg, type); //use whatever popup, notification or whatever plugin you want
   }
});
3
15.02.2011 18:09:28
ты можешь объяснить return unless request.xhr? Я имею в виду, что в конце текущего запроса, если мы добавили какие-либо flash-уведомления, мы добавили их в заголовки ответа, а затем в js мы их прочитали - круто, но я не совсем уверен, почему у нас есть вышеуказанная строка
Michael K Madison 28.06.2019 09:48:44

Назначьте сообщение в контроллере следующим образом:

  flash.now[:notice] = 'Your message'

app / views / layouts / application.js.erb - макет для запросов Ajax. Здесь вы можете просто использовать

  <%= yield %>
  alert('<%= escape_javascript(flash.now[:notice]) %>'); 

или с некоторыми богатыми анимациями, используя gritter: http://boedesign.com/demos/gritter/

  <%= yield %>
  <% if flash.now[:notice] %>
    $.gritter.add({
      title: '--',
      text: '<%= escape_javascript(flash.now[:notice]) %>'
    });
  <% end %>
5
5.08.2011 11:08:39

Основываясь на других -

(Мы передаем полный объект флэш-памяти как JSON, что позволяет нам реконструировать весь объект флэш-памяти в браузере. Это можно использовать для обеспечения отображения всех сообщений флэш-памяти в случае, если Rails генерирует несколько сообщений флэш-памяти.)

#application_controller.rb
class ApplicationController < ActionController::Base
  after_filter :flash_to_headers

  def flash_to_headers
    if request.xhr?
      #avoiding XSS injections via flash
      flash_json = Hash[flash.map{|k,v| [k,ERB::Util.h(v)] }].to_json
      response.headers['X-Flash-Messages'] = flash_json
      flash.discard
    end
  end
end
//application.js
$(document).ajaxComplete(function(event, request){
  var flash = $.parseJSON(request.getResponseHeader('X-Flash-Messages'));
  if(!flash) return;
  if(flash.notice) { /* code to display the 'notice' flash */ $('.flash.notice').html(flash.notice); }
  if(flash.error) { /* code to display the 'error' flash */ alert(flash.error); }
  //so forth
}
10
15.03.2013 06:25:59
Thnx. Я изменил функцию в application.js, чтобы она понравилась, $.each( $.parseJSON(request.getResponseHeader('X-Flash-Messages')), function(key,value){ flash_message(key,value) });если у вас есть функция js для показа флеш-сообщения с параметрами типа flash и сообщения
Rahul garg 5.02.2013 12:46:23

Я сделал это таким образом ..

контроллер :

respond_to do |format|
    flash.now[:notice] = @msg / 'blah blah...'
    format.html 
    format.js
  end

Посмотреть:

<div id='notice'>
    <%= render :partial => 'layouts/flash' , :locals => { :flash => flash } %>
</div>        

макеты / _flash.html.erb

<% flash.each do |name, msg| %>
            <div class="alert-message info"> 
                <a class="close dismiss" href="#">x</a> 
                <p><%= msg %></p>
            </div>
<% end %>

post.js.erb

$("#notice").html("<%= escape_javascript(render :partial => 'layouts/flash' , :locals => { :flash => flash }).html_safe %>");
15
15.01.2012 21:40:48
В вашем контроллере, я могу видеть опечатку, flash.now[:notice]= @msg / 'blah blah..'мне тоже было любопытно, вы бы поместили post.js.erb в путь app / assets / javascripts, не так ли?
RajG 18.12.2013 10:15:14
post.js.erb помещается в папку просмотра контроллеров, в данном случае это "views / posts / post.js.erb". msg / "бла-бла" я имел в виду msg или случайное сообщение типа "бла-бла"
dbKooper 18.12.2013 13:20:47

Существует гем под названием Unobtrusive Flash, который автоматически кодирует флеш-сообщения в cookie. Javascript на стороне клиента проверяет наличие флэш-памяти и отображает ее любым удобным для вас способом. Это работает без проблем в обычных и ajax-запросах.

3
26.03.2012 01:49:40
Решил все вопросы за меня.
W.M. 19.09.2017 10:41:09

А вот и моя версия, основанная на @emzero, с модификациями для работы с jQuery, протестирована на Rails 3.2

application_controller.rb

class ApplicationController < ActionController::Base
    protect_from_forgery

    after_filter :flash_to_headers

    def flash_to_headers
        return unless request.xhr?
        response.headers['X-Message'] = flash_message
        response.headers["X-Message-Type"] = flash_type.to_s

        flash.discard # don't want the flash to appear when you reload page
    end

    private

    def flash_message
        [:error, :warning, :notice].each do |type|
            return flash[type] unless flash[type].blank?
        end
    end

    def flash_type
        [:error, :warning, :notice].each do |type|
            return type unless flash[type].blank?
        end
    end
end

application.js

// FLASH NOTICE ANIMATION
var fade_flash = function() {
    $("#flash_notice").delay(5000).fadeOut("slow");
    $("#flash_alert").delay(5000).fadeOut("slow");
    $("#flash_error").delay(5000).fadeOut("slow");
};
fade_flash();

var show_ajax_message = function(msg, type) {
    $("#flash-message").html('<div id="flash_'+type+'">'+msg+'</div>');
    fade_flash();
};

$(document).ajaxComplete(function(event, request) {
    var msg = request.getResponseHeader('X-Message');
    var type = request.getResponseHeader('X-Message-Type');
    show_ajax_message(msg, type); //use whatever popup, notification or whatever plugin you want
});

макет: application.html.haml

        #flash-message
            - flash.each do |name, msg|
                = content_tag :div, msg, :id => "flash_#{name}"
29
1.07.2015 22:18:08
Это также работает на рельсах 3.1.0. Спасибо Виктор, работал прямо из коробки для меня.
LearningRoR 8.08.2012 21:33:02
Отличная компиляция, хотя не должна "$ (" # flash-message "). AjaxComplete (function (event, request)" be "$ (document)"?
nullnullnull 13.01.2013 02:32:31
По какой-то причине, 'разве что flash [type] .blank?' не работает должным образом в некоторых ситуациях. Действие без вспышек приведёт к предложению «ошибка, предупреждение, уведомление». Я исправил это в js, используя строку 'if (msg! = "Error, warning, note") show_ajax_message (msg, type)', но это, очевидно, хакерское решение. Я не могу понять, настоящая причина проблемы, хотя.
nullnullnull 31.01.2013 17:15:40
[:error, :warning, :notice].each {}возвращает массив, если условие возврата не выполнено, поэтому этот код нужно немного скорректировать ... но в остальном полезно.
radixhound 25.03.2013 21:49:51
Если переработан код, чтобы он не возвращал строку «ошибка, предупреждение, уведомление», а также хорошо играл с twitter-bootstrap gist.github.com/hbrandl/5253211
Hartwig 27.03.2013 10:43:20

Я создаю движок, который включает в себя некоторое поведение для application_controller для отправки флеш-сообщения в заголовке ответа, как предлагают некоторые из вас, ребята.

https://github.com/bonzofenix/flajax

1
15.01.2013 15:06:00

В случае, если вы хотите использовать вызовы AJAX, redirect_to не должен использоваться в контроллере. Скорее, флэш-сообщение должно быть явно обозначено:

В вашем_контроллере:

respond_to :js

def your_ajax_method
  flash[:notice] = 'Your message!'
end

В представлении, названном your_ajax_method_in_the_controller

your_ajax_method_in_the_controller.js.haml

:plain
  $("form[data-remote]")
    .on("ajax:success", function(e, data, status, xhr) {
      $('.messages').html("#{escape_javascript(render 'layouts/messages')}");
      setTimeout(function(){ $(".alert").alert('close') }, 5000);
    })

Пожалуйста, обратите внимание, что сообщения класса является точкой привязки для визуализации сообщений. Этот класс должен присутствовать в вашем представлении или макете приложения. Если вы используете ERB, строка становится$('.messages').html("<%= j(render 'layouts/messages') %>");

Приведенный выше JavaScript, встроенный в HAML / ERB, является ключом для отображения флэш-сообщений при использовании AJAX. Все остальные компоненты остаются такими же для вызовов не AJAX.

Вы можете использовать your_ajax_method_in_the_controller.js.coffeeили простой .js, но тогда переменные rails не будут доступны для JS / Coffee. Несмотря на то, что здесь я не использую переменные, я предпочитаю оборачивать JS в HAML, чтобы поддерживать согласованную кодовую базу.

Я использую Twitter Bootstrap для оформления сообщений, таким образом $(".alert").alert('close')исчезая из уведомления. А вот сообщения частично:

макеты / _messages.html.haml

- flash.each do |name, msg|
  - if msg.is_a?(String)
    .alert-messages
      %div{class: "alert alert-#{name == :notice ? "success" : "error"} fade in"}
        %a.close{"data-dismiss" => "alert"} 
          %i.icon-remove-circle
        = content_tag :div, msg, id: "flash_#{name}"

На всякий случай, CSS для оповещений ниже

.alert-messages {
  position: fixed;
  top: 37px;
  left: 30%;
  right: 30%;
  z-index: 7000;
}
0
2.07.2013 21:52:16

Я изменил ответ Виктора С, чтобы исправить некоторые случаи, когда flash[type].blank?не работали, как отметили немногие в комментариях.

after_filter :flash_to_headers

def flash_to_headers
   return unless request.xhr?
   response.headers['X-Message'] = flash_message
   response.headers["X-Message-Type"] = flash_type.to_s

   flash.discard # don't want the flash to appear when you reload page
end

private

def flash_message
   [:error, :warning, :notice, nil].each do |type|
     return "" if type.nil?
     return flash[type] unless flash[type].blank?
   end
end

def flash_type
   [:error, :warning, :notice, nil].each do |type|
       return "" if type.nil?
       return type unless flash[type].blank?
   end
end

Тогда отдых такой же

// FLASH NOTICE ANIMATION

var fade_flash = function() {
    $(".flash_notice").delay(5000).fadeOut("slow");
    $(".flash_alert").delay(5000).fadeOut("slow");
    $(".flash_error").delay(5000).fadeOut("slow");
};

var show_ajax_message = function(msg, type) {
    $(".flash_message").html('<div class="flash_'+type+'">'+msg+'</div>');
    fade_flash();
};

$( document ).ajaxComplete(function(event, request) {
    var msg = request.getResponseHeader('X-Message');
    var type = request.getResponseHeader('X-Message-Type');
    show_ajax_message(msg, type); //use whatever popup, notification or whatever plugin you want

});
3
7.09.2013 23:37:58

Вот моя версия (работа с кратными уведомлениями о вспышках и специальными символами в кодировке UTF-8):

Внутри ApplicationController:

after_filter :flash_to_headers
def flash_to_headers
  return unless request.xhr?
  [:error, :warning, :notice].each do |type|
    if flash[type]
      response.headers["X-Ajax-#{type.to_s.humanize}"] = flash[type]
    end
  end
  flash.discard
end

Внутри моего кофе-скрипта (твиттер-версия):

css_class = {
    Notice: 'success',
    Warning: 'warning',
    Error: 'error'
}
$(document).ajaxComplete (event, request) ->
  for type in ["Notice", "Warning", "Error"]
    msg = request.getResponseHeader("X-Ajax-#{type}")
    if msg?
      $('#notices').append("<div class=\"alert #{css_class[type]}\">#{decodeURIComponent(escape(msg))}</div>")
3
26.02.2014 16:49:20
Он должен работать с азиатскими символами с декодированием utf8 ;-)
Luc Boissaye 26.02.2014 16:50:35
нет, это не так!. Я проверил документ RFC и обнаружил, что в заголовке http поддерживаются только символы ASCII.
fengd 28.02.2014 15:10:41