[Update 9 May 2012]
This seems to work for testing flash.now
in Rails 3:
it "puts an error in the flash" do
post :create
flash[:error].should == "Sorry, that's wrong."
end
it "does not persist the flash" do
post :create
flash.sweep
flash[:error].should be_nil
end
[Update 20 April 2010]
I recently had problems testing flash.now
, and Google kept leading me back to this post. Unfortunately it doesn’t seem to work with the current version of Rails (I’m using 2.3.5 at the moment).
This post from Pluit Solutions gives an alternative approach which seems to work. I haven’t tried it with Rails 3 though.
I don’t know whether this has caught anyone else out, or whether we just didn’t read the documentation properly (it’s covered briefly on p153 of AWDwR), but I thought I’d mention it anyway.
Anyone who’s written a Rails app will know that the ‘flash’ is used to store error and status messages, usually on form submissions. Model validation failure messages automatically get copied into the flash, but you often want to do it manually too.
flash[:notice] = "User Details updated."
redirect_to edit_user_path(@user)
The gotcha comes when you want to display a message and render a page, as opposed to redirecting – for example when errors are preventing a form from being submitted. This is how not to do it:
flash[:error] = "Password doesn't match confirmation." # WRONG!
render :action => 'change_password'
The problem is that the flash is stored for the next request. Because we’re no longer doing a redirect, that means the message may appear wherever the user goes next, not just on the page that we just rendered. To avoid this, use flash.now
, which is only used for the current request:
flash.now[:error] = "Password doesn't match confirmation."
render :action => 'change_password'
The rule of thumb is to use flash
if you’re redirecting, and flash.now
if you’re rendering (either explicitly, or by dropping through to the default view for the action).
All very well, but whatever you put in flash.now
is cleared out at the end of the request, so how do you test it? The answer (for RSpec, at least) lies in a comment on this RSpec feature request – basically just add the following to spec_helper.rb
:
module ActionController
module Flash
class FlashHash
def initialize
@hash = {}
@now_hash = {}
end
def [](key)
@hash[key]
end
def []=(key, obj)
@hash[key] = obj
end
def discard(k = nil)
initialize
end
def now
@now_hash
end
def update(hash)
@hash.update(hash)
end
def sweep
# do nothing
end
end
end
end
You can now do something like this:
describe "When a user tries to change his password with an invalid verification code" do
...
it "should put an error message in the flash" do
flash.now[:error].should == "Incorrect verification code or password."
end
it "should not persist the flash" do
flash[:error].should be_nil
end
end
[tags]Ruby,Rails,flash,RSpec[/tags]