82

I am doing some exception handling in my controller, when there is an exception thrown in :create action, I will render to the :new action and show a flash message.

Everything works fine, I can see the flash message when exception caught, but when I redirect to(handly click) other page, the flash message still here. Then I redirect to another page(the second handly click), the message could disappear.

Anyone who knows what is the reason?

My controller code:

class MessagesController < ApplicationController
  rescue_from Exception, :with => :render_new

  def new
  end

  def create
  end

private
  def render_new
    flash[:alert] = t("uploading_error")
    render :action => :new
  end
end

My layout code (Haml):

%body
  #content
    - unless flash[:alert].blank?
      #alert= flash[:alert]
Zabba
  • 64,285
  • 47
  • 179
  • 207
Jimmy Huang
  • 4,252
  • 2
  • 22
  • 22

6 Answers6

170

Replace

flash[:alert] = t("uploading_error")

with

flash.now.alert = t("uploading_error")

and see if that is the result you expect?

flash[:alert] will stay around for the next page (hence it only disappears at the second redirect); but flash.now.alert will only display for the current page.

ar31an
  • 241
  • 5
  • 9
Zabba
  • 64,285
  • 47
  • 179
  • 207
46

Deciding between flash.now and regular flash is a pain in the ass and quite fragile in my experience. I use regular flash and then modify my partial which displays the flashes to delete the contents of each flash after the user has seen it. I think this is better because

a) you don't have to think about it

b) "has the user seen it?" (ie "has the flashes partial been rendered out?") is the best criterion for deciding whether or not to clear the flash, rather than any logic in your app.

My flash partial looks like this - i also use a bit of jquery just to highlight the flashes (ie make them flash yellow for a second):

<div id="flashes">

  <% if flash[:notice] %>
    <p id="flash_notice" class="messages notice"><%= flash[:notice] %></p>
    <%= javascript_tag "$('#flash_notice').effect('highlight',{},1000);" %>
  <% end %>

  <% if flash[:error] || flash[:errors] %>
    <p id="flash_errors" class="messages errors"><%= flash[:error] || flash[:errors] %></p>
    <%= javascript_tag "$('#flash_errors').effect('highlight',{},1000);" %>
  <% end %>

  <% flash[:error] = flash[:errors] = flash[:notice] = nil %>
</div>
Max Williams
  • 32,435
  • 31
  • 130
  • 197
  • Maybe a dumb question, but is it possible that doing this deletes another flash that is about to be rendered? – Bradford Nov 08 '12 at 21:47
  • @Bradford - i don't think so: i just clear the three flash keys that i've rendered. There's no way they get cleared without being rendered, and nothing can happen in between them getting rendered and cleared, since the clearing happens in the same partial. – Max Williams Sep 17 '13 at 14:04
  • Late to the game, but I love this. – Dan Barron Oct 01 '13 at 14:50
  • 1
    I just tried this. I think flash.discard(a_single_key) is better because setting the value to nil doesn't remove the key from flash. As a result, it could display an empty message for the key deleted. – TrongBang Oct 29 '17 at 03:11
34

An alternative is to use flash.clear at the end of the partial like so:

<% if !flash.empty? %>
  <div class="flash-messages-container">
    <% flash.each do |name, msg| %>
      <% if msg.is_a?(String) && [:success, :info, :error, :warning].include?(name) %>
        <div class="flash-message" data-type="<%= name %>" >
          <%= msg %>
        </div>
      <% end %>
    <% end %>
  </div>
  <% flash.clear %>
<% end %>
CoderDave
  • 935
  • 1
  • 9
  • 11
  • flash.clear is much cleaner than <% flash[:error] = flash[:errors] = flash[:notice] = nil %> – Kevin Zych Nov 15 '14 at 04:20
  • In my experience, this is the best way to do it unless you need your flash messages to persist. I don't know why templates(maybe the scaffolds do?) don't come with flash.clear by default. – Ten Bitcomb Jan 26 '15 at 21:20
  • 3
    flash.clear is not working for me. Flash is still not disappearing – Nimish Feb 19 '16 at 12:30
2

I also suggest to clear the flash inner hashes upon displaying. flash.clear will do the trick in a clean way :

      <% flash.each do |key, value| %>
       <div class="alert alert-<%= key %>">
        <%= value %>
       </div>
      <% end %>
      <% flash.clear %> #this line clears the object

http://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html#method-i-clear

thomas dh
  • 21
  • 3
1

Even this does not work......certain types of exceptions like syntax errors...will prevent any type of cookie, flash or parameters from being transferred from controller to view. Your only option is to use a session key and then clear it after showing the error.

Try your solution with a syntax error...you should see that your message won't appear in the redirected page with anything else except with a session key.....

surtep
  • 11
  • 1
1

Previously I had same problem,But now solved through this:
Try this in your code

<script type="text/javascript">
  $(document).ready(function(){
    setTimeout(function(){
    $('#flash').fadeOut();
    }, 2000);
  })
</script>
Nimish
  • 1,053
  • 13
  • 29