flash[:notice] to the extreme

I previously discussed the difference between flash.now[:notice] and flash[:notice]. I ended with a summarizing rule that says when you end an action with render, you generally want to use flash.now[:notice], and when you end an action with redirect, you want to use flash[:notice]. While simple, I hate remembering that rule, and what really complicates things is request.xhr?

 
# Toward the end of an action in a controller
if request.xhr?
  flash.now[:notice] = "Action Completed"
else
  flash[:notice] = "Action completed."
end
 

An Ajax Request (XHR) always should use flash.now. Why? Because if it's an ajax request, then the page was not reloaded, which means if you set flash[:notice], whatever request comes next from the user, will load with the flash[:notice] of the last request, which in this case, is an XHR request - in short, they will see a persistent, non-relevant, flash[:notice] from the ajax call. So the rule for choosing whether to use flash.now or flash becomes: If an action is a response to an ajax request, or if it ends with a render, use flash.now, otherwise use flash.

But That's Complicated!

True, it is complicated and requires a lot of conditional logic in your controllers. The truth is, the choice between flash and flash.now should be abstracted out. A controller should not be responsible for choosing whether to flash or flash.now.

set_flash

In application.rb define the following function.

 
def set_flash(options={})
  now = options[:now] || (request.xhr? ? true : false)
  if now
    flash.now[:notice] = options
  else
    flash[:notice] = options
  end
end
 

A simple, but powerful and helpful function. Instead of having to call flash.now or flash, you can just do this in your controllers (as opposed to the example above).

 
# Towards the end of an action in a controller
set_flash :text => "Action Completed"
 

See, no more checks for request.xhr? because set_flash has that check. Of course, you can easily override that if you wanted an xhr request to flash and not flash.now.

 
set_flash :text => "Action Completed", :now => true
 

What I really love about the set_flash method is the ability to nicely constructed flash's with a lot of meta data:

 
set_flash :klass => "error",
             :text => "Registration failed",
             :alt => "Did you fill out the form correctly?"
 

I can then build a helper method in application_helper.rb to print out a formatted flash

 
def formatted_flash
 "
<h2 class=\"#{flash[:notice][:klass] || "success"}\">#{flash[:notice][:text]}<span>#{flash[:notice][:alt]}</span></h2>
 
"
end
 

Obviously, you can customize this method to handle a lot of how to format the flash message logic and you can add your keys to your flash[:notice], like type (a flash isn't always a notice, maybe it's a warning). Don't settle for an unintelligent, string-based flash notice.

Excuse the shoddy formatting above, I'm working on it ;-)

Trackbacks & Pingbacks 1

  1. From Ruby Saved My Life - render_either - the beginning on 17 Dec 2007 at 8:42 pm

    […] do some awesome things with xml and json that I will touch on in later posts. Let’s just say that set_flash loves render_either. Any […]

Post a Comment

Your email is never published nor shared. Required fields are marked *