Как вы справляетесь с Flash Rail с Ajax-запросами? - PullRequest
75 голосов
/ 14 декабря 2008

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

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

Ответы [ 15 ]

62 голосов
/ 28 апреля 2010

Вы также можете сохранять флэш-сообщения в заголовках ответов, используя блок 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 () на свою собственную функцию прошивки javascript или попробуйте jGrowl.

29 голосов
/ 16 апреля 2012

А вот моя версия, основанная на @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}"
15 голосов
/ 08 января 2009

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

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

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

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

$("#flash_notice").html(<%=escape_javascript(flash.delete(:notice)) %>');
14 голосов
/ 16 января 2012

Я так и сделал ..

контроллер

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 %>");
9 голосов
/ 14 сентября 2011

Здание поверх других -

(Мы передаем весь флэш-объект как 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
}
6 голосов
/ 01 января 2009

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

5 голосов
/ 05 августа 2011

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

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

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

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

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

  <%= yield %>
  <% if flash.now[:notice] %>
    $.gritter.add({
      title: '--',
      text: '<%= escape_javascript(flash.now[:notice]) %>'
    });
  <% end %>
3 голосов
/ 12 сентября 2013

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

Контроллер внутреннего приложения:

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 голосов
/ 08 сентября 2013

Я изменил ответ Виктора С, чтобы исправить некоторые случаи, когда 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 голосов
/ 26 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...