All the kings horses

Posted by Matt Jankowski

Sep 27

When you get a report from your site users or your clients complaining about seeing flash messages twice or seeing a flash message on the incorrect page, don’t listen to your coworker/boss when they tell you it must be a rails bug. It’s a feature.

When you do this…

1
2
3
4
5
6
7
8
9
10
  def update
    @user = User.find params[:id]
    if @user.update_attributes params[:user]
      flash[:success] = 'User attributes have been updated'
      redirect_to user_path(@user)
    else
      flash[:failure] = 'Could not save user.'
      render :action => :edit
    end
  end

...that flash[:failure] call you’re making is going to leave the flash set for the next request to display.

Now, since you’re rendering the edit view, which is probably a form that’s going to display some errors and POST right back to #update, you might not find this in “normal” application use. But if you want to see it, you can probably just click away from that edit page to some other link, and then you’ll see your “failure” flash on the page when you didn’t expect to.

Instead of flash[:failure], use flash.now[:failure]...

1
2
3
4
      ...
      flash.now[:failure] = 'Could not save user.'
      render :action => :edit
      ...

You still access its value via flash[:failure] from your views, but it will get removed on the page render, rather than on the next request, which is what you want because you don’t want to keep it around for the next request.

From the rails docs…

This method enables you to use the flash as a central messaging system in your app. When you need to pass an object to the next action, you use the standard flash assign ([]=). When you need to pass an object to the current action, you use now, and your object will vanish when the current action is done.

One downside to this is you can’t do…


assert_equal 'Could not save user.', flash[:failure]

...in your functional tests anymore — because after the view is processed and your functional test is running, that value is already gone! Instead, you can use…


assert_select 'div.flash-failure p', 'Could not save user.'

...which will check that the view had a p element, surrounded by a div with the right class, where the p has your well written save failure copy contained in it.

So the rule is…

Additional rules to keep in mind…


Comments on this post

Tom

Sep 27

Tom said,

Ooh, flash.now is a new one on me. Useful, though. I’ll bear that in mind…

craig t mackenzie

Sep 28

craig t mackenzie said,

great! i’ve often been bugged by this, i knew about

flash.now
, but had never really understood it, you explained it very well, i’m enjoying having your feed on my google homepage! thanks!
Ryan Kuykendall

Oct 01

Ryan Kuykendall said,

Wow…I’ve seen that bug filed on a rails app I have worked on at two separate companies…The assumption was that this was a bug rather than the misunderstanding of a Rails convention.

Thanks!

Rupak Ganguly

Oct 01

Rupak Ganguly said,

Great post. Never knew about flash.now.

Dan Croak

Oct 01

Dan Croak said,

Matt,

You… complete me. You had me at flash.now.

Great post.

Neeraj Kumar

Oct 03

Neeraj Kumar said,

Add to the rule that if you are using flash in a filter then you should use flash.now even though you are using redirect.

For example let’s say that you want to ensure that an operation is performed always when the user is logged in. You setup a before_filter. In that filter if you do
1
2
3
 
    flash[:error] = 'Please login' 
   redirect_to homepage_url

then you will run into the same issue. In this case use now.

flash gets cleared when the request is actually sent to the controller. In this case since the controller was never hit, the flash remains and causes the trouble

Tammer Saleh

Oct 03

Tammer Saleh said,

Neeraj: Are you sure that’s the case? I assumed that the before_filters would count as a controller hit as far as flash works. I’ve been using normal flash in my filters, and I haven’t seen unexpected behavior…

James Higginbotham

Oct 05

James Higginbotham said,

Great post! I too struggled with this during my first Rails app until I figured out the secrets of flash.now


Sorry, comments are closed for this article.

© 2000 - 2009 by thoughtbot, inc.
written by a bushel of tiny robots