Reputation: 45094
I did an upgrade from Rails 3.2 to 4.0 and now none of my flash messages work after a redirect.
I checked to make sure it's not a problem with the way I'm displaying the flash messages. Flash messages that don't involve a redirect work fine.
I dug into it and noticed something interesting. If I put a Pry on the controller action I redirect to, I can see that session["flash"]
is nil
. I don't believe session["flash"]
should be nil
at that point.
If I enter session.keys
into the console, it shows me this:
["session_id", "kmq", "warden.user.user.key", "_csrf_token", "foo"]
# "foo" is something I added myself as a test
Shouldn't there be a session key called "flash"
?
I look at the FlashHash source code and I see that flash messages apparently get saved not only to the session, but also to @env
. So I performed the following experiment.
# I'm manually setting a flash message
> flash[:notice] = "hello"
# Now I'm checking for the flash message in env
> env["action_dispatch.request.flash_hash"]
=> #<ActionDispatch::Flash::FlashHash:0x007fda544718b0
@discard=#<Set: {}>,
@flashes={:notice=>"hello"},
@now=nil>
# Now I'm checking for it in the session
> session["flash"]
=> nil
And then if I do a Pry on the controller action to which my redirect goes, I can do this:
> env["action_dispatch.request.flash_hash"]
And it returns nil
.
My HashFlash
evidently makes it into env
sometimes, session
never. The fact that it never gets into session
strikes me as probably incorrect behavior.
def update
user_params.delete(:password) if user_params && user_params[:password].blank?
if user.update_attributes(user_params)
respond_to do |format|
format.html do
redirect_to(user_account_path(user, anchor: params[:tab]), notice: "Your account has been updated")
end
format.js
end
else
render :show
end
end
I know for a fact that control is getting to the redirect. I've also tried changing the code to this with no luck.
def update
# Redirect right away to kill the extra moving parts
redirect_to(user_account_path(user, anchor: params[:tab]), notice: "Your account has been updated")
return
user_params.delete(:password) if user_params && user_params[:password].blank?
if user.update_attributes(user_params)
respond_to do |format|
format.html do
redirect_to(user_account_path(user, anchor: params[:tab]), notice: "Your account has been updated")
end
format.js
end
else
render :show
end
end
So my question is: how can I get my flash messages to work again?
Edit: When I manually set session["flash"]
to flash.to_session_value
, the flash message comes across, although then it's permanently "stuck on". That seems like a clue, though.
Edit 2: I've learned, by doing some inspection on a known-working project, that session["flash"]
can never be expected to be present immediately after assigning a value to flash[:notice]
(or whatever other key). Apparently the flash messages are only plugged into session
after the controller action returns. So that solves that part of the mystery.
Edit 3: FWIW, here's the output of rake middleware
:
use Airbrake::UserInformer
use Rack::Sendfile
use ActionDispatch::Static
use Rack::Lock
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fcc23268eb8>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use BetterErrors::Middleware
use Airbrake::Rails::Middleware
use ActionDispatch::RemoteIp
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::ActiveRecordStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Warden::Manager
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use OmniAuth::Builder
run DueProps::Application.routes
I don't know if that provides any clues or not.
Upvotes: 4
Views: 2077
Reputation: 45094
I found the culprit. Someone had added this in config/application.rb
:
use ActionDispatch::Cookies
use ActionDispatch::Session::ActiveRecordStore
Thus, rake middleware
was showing two each of ActionDispatch::Cookies
and ActionDispatch::Session
:
use ActionDispatch::Cookies
use ActionDispatch::Session::ActiveRecordStore
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
Once we removed those two lines, flash messages worked once again.
I have to thank @jbgo because his comment is what led me to the solution.
Upvotes: 3