Flash not accessible in tests (TypeError: can't convert String into Integer)
This morning I faced a strange problem when trying to write RSpec tests for a user login action. Trying to setting the flash before doing a request, resulted in an unexpected Exception:
TypeError in 'SessionController logging in with correct credentials should redirect to the url_after_login url if given'
can't convert String into Integer
.../vendor/plugins/rspec_on_rails/lib/spec/rails/dsl/behaviour/functional.rb:80:in 'flash'
./spec/controllers/session_controller_spec.rb:52:
./script/spec:4:
After some debugging, I found out that session
delegates to @request.session
and flash
delegates to @response.session['flash']
. It turned out, that before doing a test-request (by calling get
or post
), @response.session
is initialized to an empty array (in ActionController::AbstractResponse#initilaize
), while @request.session
is properly initialized to ActionController::TestSession
.
So, trying to access the flash
delegates to @response.session['flash']
, which throws a TypeError, because @response.session
is an array and an array index is expected to be an integer, not a string.
This problem seems to only occur when trying to access the flash
in a test before doing the actual request (which I needed to do in my case to set the URL that the controller should redirect to after a login). Setting session values itself doesn't seem to be affected, because session
delegates to @request.session
, which is properly initialized with ActionController::TestSession.new
.
If you also face this problem in your tests or specs, you can easily work around it by manually initializing the response's session. Just add
response.session = ActionController::TestSession.new
to your setup
method (or to your before(:each)
block if you use RSpec).
Somebody already submitted a ticket concerning this (or a similar) problem 3 months ago: Ticket #8939. Unfortunately, it was flagged incomplete. Lets see if I can put together and submit a patch later today...
Update
The above workaround does indeed fix the TypeError problem, but setting the flash
before doing the test-request doesn't seem to affect the flash
that the tested controller sees. Therefore, values set to the flash
do not affect the controller. It looks like this problem goes deeper into the rails core than I was expecting. For now, here's a (working) workaround to set the flash for now. Instead of flash[:key]=value
, use:
controller.send(:flash)[:key] = value
Update 2007-09-24
You live and learn... As mpalmer points out in Ticket #8939, you aren't supposed to access the flash hash before doing a test request. Instead, the flash can be set by giving a 4th parameter to the get
or post
method:
get :login, { :username => ..., :password => ... }, {}, { :url_after_login => ... }
This isn't as intuitive as I expected it to be (like setting the flash hash directly), but it works fine...