Rails flash notice via ajax

47,807

Solution 1

Here is an example that I got working, thanks to Rich Peck's answer. I needed to use flash.now to make sure the flash notice didn't persist.

AJAX trigger in the view:

<%= link_to "Email report", users_path, remote: true %>

Controller:

# app/controllers/users_controller
class UsersController < ApplicationController

  def index
    # do some things here

    respond_to do |format|
      format.js { flash.now[:notice] = "Here is my flash notice" }
    end
  end
end

Rendered view:

# app/views/users/index.js.erb
$("#flash").html('<%= j render partial: "shared/notice_banner" %>');

where the flash notice is displayed in the layout:

# app/views/layouts/application.html.erb
<div id="flash">
  <% if notice.present? %>
    <%= render partial: "shared/notice_banner" %>
  <% end %>
</div>


# app/views/shared/_notice_banner.html.erb
<div data-alert class="alert-box">
  <%= notice %>
  <a href="#" class="close">&times;</a>
</div>

Solution 2

Sessions

the same notice persists on the next clicks too

This is caused by the flash being stored in the session variable of Rails:

The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for passing error messages etc.

The problem you have is that since I don't think ajax counts as a new request (need reference for this), the data will persist into the next time you request via HTTP.

--

Fix

I would initially try this:

def show
    respond_to do |format|
        format.js {  flash[:notice] = "my secret number "+rand(0,5)+" !" }
    end
end

The main problem you have is you're processing the flash variable in your JS using the ERB preprocessor. This is an issue as it means you won't be able to use asset precompile to help it work.

After looking at this question, why not try using the after_filter callback, like this:

#app/controllers/home_controller.rb
Class Home < ActionController::Base
   after_filter { flash.discard if request.xhr? }, only: :show

    def show
        respond_to do |format|
            format.js {  flash[:notice] = "my secret number "+rand(0,5)+" !" }
        end
    end
end

--

Update

You should include the success functionality in your show.js.erb:

#app/views/home/show.js.erb
$("#notice").html("<%= flash[:notice] %>");

This means you can remove the whole ajax call from the application.js, and replace with the remote: true for your search form:

#app/views/search/index.html.erb
<%= form_tag home_show_path, remote: true %>

The reason this works is because when you use the format.js respond block, Rails will load the [action].js.erb file in your views. Considering this only happens after the action has been completed, it's equivalent to the success function of your ajax.

By doing this, you'll be able to remove the entire ajax function from your application.js, and replace with the UJS version, as described above

Share:
47,807
Santino 'Sonny' Corleone
Author by

Santino 'Sonny' Corleone

We don't discuss business at the table.

Updated on January 07, 2020

Comments

  • Santino 'Sonny' Corleone
    Santino 'Sonny' Corleone over 4 years

    Long story short, I have a button. On clicking it, I want an ajax request to be triggered which gets flash[:notice] and displays it in a div in$

    Here is my shortened view:

     <input type="button" id="search" value="display"/>
    
     <div id="notice">
    
     </div>
    

    My ajax request in the view:

    $("#search").submit(function(){
                                $.ajax({
                                    type: "POST",
                                    url: //url to my show action
                                    success: function(data){
                                          /*$("#notice").html("<%= flash[:notice] %>");
                                            $("#content").html(data);*/
                                    }
                                });
                                return false;
                        });
    

    My controller:

    def HomeController <  ActionController::Base
      def index
    
      end
    
      def show
        respond_to do |format|
        format.js {  flash[:notice] = "" + count.to_s + " results found for " + params[:query][:search_key] + "" }
        end
        #render :partial => 'search'
      end
    end
    

    My show.js.erb

    #app/views/dashboard_home/show.js.erb
    $("#notice").html("<%=j flash[:notice] %>");
    
    $("#content").html("<%=j render partial: "search" %>");
    

    The problem is when I click on button, the notice is displayed fine. But the same notice persists on the next clicks too. The search partial contains the table Please help!

  • Santino 'Sonny' Corleone
    Santino 'Sonny' Corleone almost 10 years
    thnx..but how should i access the flash notice in the ajax success function?
  • Richard Peck
    Richard Peck almost 10 years
    You'll be better creating show.js.erb in your views/home folder - this will load that file with the ERB preprocessor, consequently allowing you to show the flash message. Since this file is exclusive of the asset pipeline, it won't get lost when you precompile the assets :)
  • Santino 'Sonny' Corleone
    Santino 'Sonny' Corleone almost 10 years
    so shud i put the whole ajax fn in the show.js.erb?
  • Richard Peck
    Richard Peck almost 10 years
    Well all you can hope for now is a miracle!
  • Richard Peck
    Richard Peck almost 10 years
    I joke...... you need to give me information. A response; is it not firing? Is the Ajax working or not?
  • Richard Peck
    Richard Peck almost 10 years
    Don't give up that easily. Tell me what is happening - I want to fix this
  • Santino 'Sonny' Corleone
    Santino 'Sonny' Corleone almost 10 years
    the ajax works fine...i get the search results but i dont get the flash notice saying "these many records were found"..i wont give up...
  • Richard Peck
    Richard Peck almost 10 years
    Okay - have you used the show.js.erb? What about your ajax- just using remote: true ?
  • Richard Peck
    Richard Peck almost 10 years
  • Santino 'Sonny' Corleone
    Santino 'Sonny' Corleone almost 10 years
    but do i need to put the full ajax function in show.js.erb?ajax has remote:true