Pregunta ¿Cómo manejas el flash de Rail con las solicitudes de Ajax?


Estoy muy feliz con la solución que se me ocurrió Básicamente, tengo un método de ayuda que recarga el flash en línea, y luego tengo un after_filter que borra el flash si la solicitud es xhr. ¿Alguien tiene una solución más simple que eso?

Actualizar: La solución anterior fue escrita en Rails 1.x y ya no es compatible.


74
2017-12-14 08:40


origen


Respuestas:


También puede almacenar los mensajes flash en los encabezados de respuesta usando un bloque after_filter y mostrarlos usando 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

Y en application.js agrega un controlador global de ajax. Para jquery haz algo como esto:

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

Reemplace la alerta () con su propia función flash de JavaScript o pruebe jGrowl.


61
2018-04-28 12:43



Y aquí está mi versión basada en @emzero, con modificaciones para trabajar con jQuery, probado en 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
});

diseño: application.html.haml

        #flash-message
            - flash.each do |name, msg|
                = content_tag :div, msg, :id => "flash_#{name}"

29
2018-04-16 01:14



Esto es necesario en la respuesta js

Si está utilizando RSJ:

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

Si está usando jQuery:

$("#flash_notice").html(<%=escape_javascript(flash.delete(:notice)) %>');

15
2018-01-08 11:28



Lo hice de esta manera ...

controlador:

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

ver:

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

layouts / _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 %>");

14
2018-01-15 21:40



Construyendo sobre otros -

(Pasamos el objeto flash completo como JSON, lo que nos permite reconstruir el objeto flash completo en el navegador. Esto se puede utilizar para garantizar que todos los mensajes flash se muestren en caso de que Rails genere varios mensajes flash).

#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
}

9
2017-09-14 10:11



Parece que lo que necesitas es flash.now[:notice], que solo está disponible en la acción actual y no en la siguiente. Puede echar un vistazo a la documentación aquí: http://api.rubyonrails.com/classes/ActionController/Flash/FlashHash.html#M000327


6
2018-01-01 18:51



Asigna el mensaje en el controlador de esta manera:

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

app / views / layouts / application.js.erb - Diseño para solicitudes Ajax. Aquí puedes simplemente usar

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

o con algunas animaciones ricas usando Gritter: http://boedesign.com/demos/gritter/

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

5
2017-08-05 11:08



Basado en la respuesta gudleik:

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

Luego, en su application.js (si usa Rails native Prototype helpers) agregue:

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
2018-02-15 18:09



Hay una gema llamada Destello discreto que codifica automáticamente los mensajes flash en una cookie. Un javascript en el cliente comprueba flash y lo muestra de la forma que desee. Esto funciona a la perfección tanto en solicitudes normales como ajax.


3
2018-03-26 01:49