Rails flashes (FlashHash
) track a list of used keys, which is not respected when comparing flash hashes.
This does not concern you under most circumstances.
Basics
When ActionController
picks up a flash object, it will call the #sweep
method once; that method checks the list of used flash entries and deletes those. All other entries are flagged as used. This means they will be deleted on the next request, but are still be available for rendering during the current request.
Fun facts: When redirecting, this does not happen. Also, using #keep
on a flash will reset that list of used records.
The issue
You will rarely run into this, but: assume you want to compare two FlashHash
objects:
>> flash1
=> {:hello=>"Universe"}
>> flash2
=> {:hello=>"Universe"}
>> flash1 == flash2
=> true
So far so good. But: When flash1
was sweep
ed while flash2
was not this happens:
>> flash1.instance_variable_get('@used')
=> {:hello=>true}
>> flash2.instance_variable_get('@used')
=> {:hello=>false}
>> flash1 == flash2
=> true
While the keys are still the same, both flashes actually are not the same, since one will discard its records when processing the next request, while the other will not.
Monkey-patch away
While you don't want to change "regular" comparison methods (like ==
or eql?
), you can use this initializer to get a FlashHash#same?
method which checks for that:
ActionController::Flash::FlashHash.class_eval do
# This is from a Rails 2 project. For Rails 3, say:
# ActionDispatch::Flash::FlashHash.class_eval do
def same?(other_flash)
self == other_flash && used == other_flash.used
end
protected
def used
@used
end
end
There you go:
>> flash1.same? flash2
=> true
>> flash1.sweep
>> flash1.same? flash2
=> false