2

我在 Sinatra 中为 编写了一个快速帮助程序redirect_to_next,我在其中重定向到由提供的路径(session[:next]如果存在)或默认路径。

在 Sinatra 中,session真正由 Rack 和spec提供,据说它为fetch. 我写了以下错误助手来解释我的问题。

error 401 do
  session[:next] = request.path
  puts "get   #{session[:next]}"
  puts "fetch #{session.fetch(:next, '/')}"
  redirect "/login"
end

当我在未登录的情况下尝试访问/settingshalt 401时,我会运行上面的代码。这是它打印到我的终端的内容:

get   /settings
fetch /

:next作为键存在,那么为什么它给我默认值,就好像它没有一样?

更新

这个最小的例子显示了相同的行为。

require 'sinatra'

set :sessions, true

get '/' do
  session[:testing] = "hello"
  puts "get   #{session[:testing]}"
  puts "fetch #{session.fetch(:testing, 'goodbye')}"
end

日志

[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

软件

  • 红宝石 (1.9.3p194)
  • 机架 (1.4.1)
  • 西纳特拉 (1.3.2)
4

1 回答 1

3

会话哈希不是普通的 Ruby Hash,而是Rack::Session::Abstract::SessionHash. SessionHash实际上继承自Hash,但它覆盖了[]= and方法,在存储和检索它们之前[]调用to_s任何键。

扩展您的更新示例:

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

给出这个输出:

get               hello
fetch             goodbye
fetch with string hello

当您使用Hash#fetch,传递一个符号时,该方法会直接分派到父哈希,而不是转换为字符串,因此找不到匹配的键。

因此,始终在会话中使用字符串作为键,一切都应该正常工作。

于 2012-04-29T22:01:21.040 回答