Comment gérez-vous le flash de Rail avec les requêtes Ajax?

Je suis plutôt content de la solution que j’ai trouvée . Fondamentalement, j’ai une méthode d’assistance qui recharge le flash en ligne, puis j’ai un after_filter qui efface le flash si la requête est xhr. Quelqu’un at-il une solution plus simple que cela?

Mise à jour: La solution ci-dessus a été écrite dans Rails 1.x et n’est plus prise en charge.

Vous pouvez également stocker les messages flash dans les en-têtes de réponse à l’aide d’un bloc after_filter et les afficher en utilisant 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 

Et dans application.js, ajoutez un gestionnaire ajax global. Pour jquery faire quelque chose comme ça:

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

Remplacez alert () par votre propre fonction flash javascript ou essayez jGrowl.

Et voici ma version basée sur @emzero, avec des modifications pour fonctionner avec jQuery, testé sur 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('
'+msg+'
'); 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 });

mise en page: application.html.haml

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

Ceci est nécessaire dans la réponse de js

Si vous utilisez RSJ:

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

Si vous utilisez jQuery:

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

Je l’ai fait de cette façon ..

contrôleur :

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

vue:

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

layouts / _flash.html.erb

 < % flash.each do |name, msg| %> 
x

< %= msg %>

< % end %>

post.js.erb

 $("#notice").html("< %= escape_javascript(render :partial => 'layouts/flash' , :locals => { :flash => flash }).html_safe %>"); 

Construire sur les autres –

(Nous transmettons l’object Flash complet en tant que JSON, ce qui nous permet de reconstruire l’object Flash complet dans le navigateur. Cela peut être utilisé pour s’assurer que tous les messages Flash sont affichés si plusieurs messages Flash sont générés par 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 } 

On dirait que ce dont vous avez besoin est flash.now[:notice] , qui n’est disponible que dans l’action en cours et non dans l’action suivante. Vous pouvez consulter la documentation ici: http://api.rubyonrails.com/classes/ActionController/Flash/FlashHash.html#M000327

Atsortingbuez le message dans le contrôleur comme ceci:

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

app / views / layouts / application.js.erb – Mise en page des requêtes Ajax. Ici, vous pouvez simplement utiliser

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

ou avec quelques animations riches utilisant gritter: http://boedesign.com/demos/gritter/

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

Basé sur gudleik répond:

 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 

Ensuite, sur votre application.js (si vous utilisez les assistants Prototype natifs de Rails), ajoutez:

 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 } }); 

Il existe un joyau appelé Flash non intrusif qui encode automatiquement les messages flash dans un cookie. Un javascript à la fin du client vérifie le flash et l’affiche comme vous le souhaitez. Cela fonctionne parfaitement dans les requêtes normales et ajax.

J’ai modifié la réponse de Victor S pour corriger certains cas où flash[type].blank? n’a pas fonctionné comme noté par quelques personnes dans les commentaires.

 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 

Alors le repos est le même

 // 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('
'+msg+'
'); 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 });

Voici ma version (travail avec plusieurs avis flash et caractères spéciaux encodage UTF-8):

Inside 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 

Dans mon script café (version bootstrap twitter):

 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("
#{decodeURIComponent(escape(msg))}
")

Une autre façon serait de mettre à jour / afficher le div “notice” avec le message du gestionnaire “OnFailure” de vos requêtes Ajax. Cela vous permet d’afficher ces messages flash avec l’effet requirejs. J’ai utilisé ça

  render: text => "Une erreur est survenue",: status => 444

dans le Javascript

  nouveau AjaxRequest (...

   ,
    OnFailure: fonction (transport) {
       $ ("# notice"). update (transport.responseText);
      // montre le message  
    }

 );

HTH

Je construis un moteur qui inclut un comportement à l’application_controller pour envoyer le message flash dans l’en-tête de réponse, comme certains le proposent.

https://github.com/bonzofenix/flajax

La seule amélioration à laquelle je peux penser est de faire en sorte que page.reload_flash soit par défaut (ne pas avoir à le placer sur tous les fichiers rjs, et le rendre explicite si vous ne voulez pas recharger le flash, quelque chose comme page.keep_flash.

Je ne saurais pas par où commencer mais connaissant quelques rails, je suis sûr que ce n’est pas si difficile.

Si vous souhaitez utiliser les appels AJAX, redirect_to ne doit pas être utilisé dans le contrôleur. Au contraire, le message flash devrait être explicitement noté:

Dans votre contrôleur:

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

Dans la vue nommée par 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); }) 

Veuillez noter que la classe de messages est un point d’ancrage pour le rendu des messages. Cette classe doit être présente dans votre vue ou dans la présentation de l’application. Si vous utilisez ERB, la ligne devient $('.messages').html("< %= j(render 'layouts/messages') %>");

Le code JavaScript ci-dessus intégré à HAML / ERB est la clé de l’affichage des messages flash lors de l’utilisation d’AJAX. Tous les autres composants restnt les mêmes pour les appels non-AJAX.

Vous pouvez utiliser your_ajax_method_in_the_controller.js.coffee ou plain .js mais les variables de rails ne seront pas disponibles pour JS / Coffee. Même si je n’utilise pas de variables ici, je préfère envelopper JS dans HAML pour conserver une base de code cohérente.

Je mets à profit Twitter Bootstrap pour les messages de style, donc $(".alert").alert('close') disparaît de la notice. Et voici les messages partiels:

layouts / _messages.html.haml

 - flash.each do |name, msg| - if msg.is_a?(Ssortingng) .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}" 

Au cas où, CSS pour les alertes est ci-dessous

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