Reputation: 1617
According to the Flash documentation, I should be able to pass strings, arrays or hashes through Flash. Strings and arrays work fine but hashes aren't working.
Here's a stripped down (but still failing) version of my code:
# views/layouts/flash_messages.html.haml
- flash.each do |type, content|
- message = content if content.class == String
- message, detail = content if content.class == Array
- message, detail = content[:message], content[:detail] if content.class == Hash
- if message || detail
.alert
%h3= message if message.present?
%p= detail if detail.present?
class HomeController < ApplicationController
def index
end
def test_string
redirect_to root_url, alert: 'Plain string works'
end
def test_array
redirect_to root_url, alert: ['Array works', 'Tested with 0, 1, 2 or more items without problems']
end
def test_hash
redirect_to root_url, alert: {message: 'Hash not working :(', detail: 'Even though I think it should'}
end
end
The problem seems to be with the assignment line in the case of the hash, the keys are present but method
and detail
always end up nil for hashes. But when I try the same code in the console it works fine...
irb> content = { message: 'This hash works...', detail: '...as expected' }
=> {:message=>"This hash works...", :detail=>"...as expected"}
irb> message, detail = content[:message], content[:detail] if content.class == Hash
=> [ 'This hash works...', '...as expected' ]
irb> message
=> 'This hash works...'
irb> detail
=> '...as expected'
Upvotes: 0
Views: 247
Reputation: 1617
Closer inspection revealed that, while the keys were indeed set, they'd been converted from symbols to strings.
To fix this I had to change line 4 of the controller from symbols to strings:
- message, detail = content[:message], content[:detail] if content.class == Hash
- message, detail = content['message'], content['detail'] if content.class == Hash
If I understand correctly, this is a result of flashes being stored in the session and the session object being stored in cookies as JSON objects. JSON doesn't support symbolised keys.
As an experiment I tried setting matching string and symbol keys. If you try doing both in one assignment, Ruby takes the first key and the second value (with a warning):
irb> content = { message: 'Symbol key first', 'message': 'String key second' }
=> warning: key :message is duplicated and overwritten on line X
=> {:message=>"String key second"}
But if you deliberately duplicate the keys in a hash passed to flash, whichever one is defined last "wins" (in my limited testing, but it makes sense given hashes are most likely iterated in insertion order):
symbol_first = {}
symbol_first[:message] = 'Symbol wins'
symbol_first['message'] = 'String wins'
flash[:alert] = symbol_first # 'String wins' is displayed
string_first = {}
string_first['message'] = 'String wins'
string_first[:message] = 'Symbol wins'
flash[:alert] = string_first # 'Symbol wins' is displayed
Upvotes: 2