Reputation: 859
I was writing a quick helper in Sinatra for redirect_to_next
, where I redirect to the path provided by session[:next]
if it exists, or a default.
In Sinatra, session
really provided by Rack, and by spec, it is said to provide a hash like interface for fetch
. I wrote the following error helper to explain my problem.
error 401 do
session[:next] = request.path
puts "get #{session[:next]}"
puts "fetch #{session.fetch(:next, '/')}"
redirect "/login"
end
When I attempt to access /settings when not logged in, I halt 401
which runs the above code. This is what it prints to my terminal:
get /settings
fetch /
:next
exists as a key, so why is it giving me the default as if it does not?
Update
This minimal example shows the same behavior.
require 'sinatra'
set :sessions, true
get '/' do
session[:testing] = "hello"
puts "get #{session[:testing]}"
puts "fetch #{session.fetch(:testing, 'goodbye')}"
end
Logs
[2012-04-29 14:11:51] INFO WEBrick::HTTPServer#start: pid=1954 port=9292
get hello
fetch goodbye
10.0.2.2 - - [29/Apr/2012 14:11:54] "GET / HTTP/1.1" 200 - 0.0485
Software
Upvotes: 2
Views: 347
Reputation: 79783
The session hash isn’t a normal Ruby Hash
, it’s a Rack::Session::Abstract::SessionHash
. SessionHash
actually inherits from Hash
, but it overrides the []=
and []
methods, calling to_s
on any keys before storing and retrieving them.
Extending your update example:
require 'sinatra'
set :sessions, true
get '/' do
session[:testing] = "hello"
puts "get #{session[:testing]}"
puts "fetch #{session.fetch(:testing, 'goodbye')}"
puts "fetch with string #{session.fetch(:testing.to_s, 'goodbye')}"
end
gives this output:
get hello
fetch goodbye
fetch with string hello
When you use Hash#fetch
, passing a symbol, the method gets dispatched directly to the parent hash, without being converted to a string, and so the matching key isn’t found.
So, always use Strings as keys in your sessions and everything should work.
Upvotes: 3