Kenny Zhang
Kenny Zhang

Reputation: 63

How to display flash messages, on successful ajax, at the top of my page, without refreshing?

My bookmarks index page is essentially a single page application. When I submit the form for a new bookmark at the bottom of my page, I want the page to not have to refresh and display "Bookmark successfully created!" in the form of a flash message at the top of the page.

In my application.html.erb file, I am rendering flash messages:

<!DOCTYPE html>
<html>
<head>
  <title>Text Me Later</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= render partial: 'layouts/nav' %>

<% flash.each do |key, value| %>
  <% if key == "notice" %>
    <%= content_tag :div, value, class: "text-center alert alert-warning" %>
  <% elsif key == "alert" %>
    <%= content_tag :div, value, class: "text-center alert alert-danger" %>
  <% else %>
    <%= content_tag :div, value, class: "text-center alert alert-success" %>
  <% end %>
<% end %>

<div class="container">

<%= yield %>

<%= debug(params) if Rails.env.development? %>

</body>
</html>

The create method in my bookmarks_controller:

def create
    @bookmark = Bookmark.new bookmark_params
    @bookmark.user_id = current_user.id

    respond_to do |format|
      if @bookmark.save
        flash[:notice] = 'Bookmark was successfully created.'
        format.html { 
          redirect_to user_bookmarks_path
        }
        format.json { 
          render json: @bookmark,
          status: :created, 
          location: @bookmark
        }
        format.js {}
      else
        flash[:error] = "Bookmark could not be created."
        format.html {
          render :index
        }
        format.json {
          render json: @bookmark.errors.full_messages
        }
        format.js {}
      end
    end
  end

My bookmarks index.html.erbfile:

<h2>All of <%= current_user.first_name %>'s Bookmarks</h2>
<ul id="all-bookmarks">
    <% @bookmarks.each do |bookmark| %>
    <li class="bookmark-div">
            <div><%= bookmark.title %></div>
            <div><%= bookmark.image %></div>
            <div><%= bookmark.description %></div>
            <div><%= bookmark.location %></div>
            <div><%= bookmark.time %></div>
            <div><%= bookmark.date %></div>
            <div><%= bookmark.created_at %></div>
            <div><%= bookmark.updated_at %></div>
            <div><%= bookmark.url %></div>
            <div><%= link_to "Edit", [:edit, bookmark]%></div>
            <div><%= link_to "Delete Bookmark", bookmark, :method => :delete, confirm: 'are you sure?'%></div>
            <div><%= link_to "Add as a reminder" %></div>
    </li>
    <% end %>
</ul>

<h2>Add a bookmark below:</h2>

    <div id="post-new-bookmark">
        <%= simple_form_for [@user, @bookmark], :method => :post, remote: true do |f| %>
            <% if @bookmark.errors.any? %>
             <div id="errorExplanation">
              <h2><%= pluralize(@bookmark.errors.count, "error") %> prohibited this post from being saved:</h2>
              <% end %>
            <%= f.input :title %>
            <%= f.input :image %>
            <%= f.input :description %>
            <%= f.input :location %>
            <%= f.input :date %>
            <%= f.button :submit %>
        <% end %>
    </div>

create.js.erb:

$("<%= escape_javascript(flash[:notice]) %>").appendTo("#flash-notice")

$("<%= escape_javascript render(:partial => 'bookmarks/cbookmark', :locals => { :bookmark => @bookmark }) %>").appendTo("#all-bookmarks")

My question is: Why is the flash message on successful bookmark creation not displaying at the top of the page right after a successful creation? Shouldn't the flash message handling in my application.html.erbtake care of it? Could it be due to a syntax error in my bookmark controller? I also have a question about flash.now vs flash. Is that relevant in this case since the bookmark submission is an AJAX action?

Upvotes: 1

Views: 3698

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

form of a flash message

Ce ne pas possible avec le flash de Rails

--

The flash forms part of the session cookie that Rails populates between actions. This has been notoriously difficult to parse with Ajax, and indeed remains a difficult pattern to implement (how can Rails repopulate the session when your browser hasn't been refreshed).

The way to go about it is to pass the value through your ajax method, using flash.now. Good ref here (I wrote about it):

#app/controllers/bookmarks_controller.rb
class BookmarksController < ApplicationController
   def create
    @bookmark = Bookmark.new bookmark_params
    @bookmark.user_id = current_user.id

    respond_to do |format|
      if @bookmark.save
        flash.now[:notice] = 'Bookmark was successfully created.'
        format.html { redirect_to user_bookmarks_path }
        format.json { render json: @bookmark, status: :created, location: @bookmark }
        format.js
      else
        flash.now[:error] = "Bookmark could not be created."
        format.html { render :index }
        format.json { render json: @bookmark.errors.full_messages }
        format.js
      end
    end
  end
end

Using flash.now should allow you to populate the flash through Ajax accordingly:

#app/views/bookmarks/create.js.erb
$("<%=j flash.now[:notice]  %>").appendTo("#flash-notice")

Upvotes: 1

Related Questions