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…
- Use flash when you’re going to redirect, so that the next action will be able to display the flash value
- Use flash.now when you’re going to render, so that the current view can display the value and the next view won’t (additionally and wrongly) display it.
Additional rules to keep in mind…
- Use the flash at the top of a page to tell someone THAT they are not fit to be using your app
- Use error_messages_for down in the view to tell them WHY they are not fit to be using your app
Comments on this post
Sep 27
Tom said,
Ooh, flash.now is a new one on me. Useful, though. I’ll bear that in mind…
Sep 28
craig t mackenzie said,
great! i’ve often been bugged by this, i knew aboutOct 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!
Oct 01
Rupak Ganguly said,
Great post. Never knew about flash.now.
Oct 01
Dan Croak said,
Matt,
You… complete me. You had me at flash.now.
Great post.
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 doflash[:error] = 'Please login' redirect_to homepage_urlthen 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
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…
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
Come “ride the toad” on Hoptoad, the app error app.
Thunder Thimble: Brand monitoring for social media.
Widgetfinger: Simple content management for simple websites.
Tee-Bot, funny shirts your friends won't understand!
Umbrella Today: “It’s like totally the simplest weather report ever, Julie.”
Thoughtbot
thoughtbot is a technology consulting firm that provides web application development and design services. We focus on building modern systems, embracing good ideas and delivering elegant solutions.
Interested in learning Rails?
Sign up for our beginning or advanced training.
Archives