加载该会话的力如何?
Posted
技术标签:
【中文标题】加载该会话的力如何?【英文标题】:How force that session is loaded? 【发布时间】:2013-01-17 21:15:10 【问题描述】:我正在开发一个需要使用会话 ID 信息的应用程序。我的会话存储在 cookie 中。我遇到的问题是,当用户第一次访问该站点时,控制器无法立即使用我的会话。我想我可能遗漏了一些关于如何在 Rails 中初始化会话的信息。但我对会话未加载这一事实持肯定态度,因为这是session.inspect
的输出:
#<Rack::Session::Abstract::SessionHash:0x15cb970 not yet loaded>
这里是如何重现 Rails 3.2.11
和 ruby 1.9.3
的问题:
使用test
控制器创建一个新应用程序:
rails new my_app
cd my_app/
rails g controller test
rm app/assets/javascripts/test.js.coffee
touch app/views/test/index.html.erb
尝试在该控制器中获取会话 ID:
class TestController < ApplicationController
def index
puts session[:session_id]
puts session.inspect
end
end
添加需要的路由:
MyApp::Application.routes.draw do
resources :test
end
然后访问应用程序并查看它的作用:
rails server
转至:http://localhost:3000/test
那是控制台中的输出:
#<Rack::Session::Abstract::SessionHash:0x3fd10f50eea0 not yet loaded>
然后是http://localhost:3000/test
,这次我们有一个会话:
400706c0b3d95a5a1e56521e455075ac
"session_id"=>"400706c0b3d95a5a1e56521e455075ac", "_csrf_token"=>"Euaign8Ptpj/o/8/ucBFMgxGtiH7goKxkxeGctumyGQ="
【问题讨论】:
尝试强制会话加载:[***.com/questions/1035933/rails-2-3-session][1][1]:***.com/questions/1035933/rails-2-3-session 这是一个很好的提示。到目前为止,我在那里尝试了几种方法都没有成功。 我刚刚在一个干净的项目中尝试过,我的会话总是被加载。我似乎没有重现您的问题。你可以试着给我们更多的代码来看看。 @joscas 好的,我得到了错误,但只有在我第一次运行 rails 服务器时,如果我退出服务器并重新启动它,我就不会再收到错误了。我将在生产环境中尝试它,看看那里会发生什么。 你可能想追踪this issue。 【参考方案1】:我找到了一种强制初始化会话的方法。访问会话显然不会强制初始化,但写入会话会。我现在在控制器中所做的是:
class MyController < ApplicationController
protect_from_forgery
def index
session["init"] = true
do_stuff
end
end
我仍然不确定这是否应该被视为 Rails 中的正常行为。在我看来,必须写入会话来强制初始化是不对的。读书应该够了。
【讨论】:
【参考方案2】:我同意@joscas 的回答,但我不会写一个值,而是将其删除,以免有冗余数据。
class MyController < ApplicationController
protect_from_forgery
def index
session.delete 'init'
do_stuff
end
end
会话也以这种方式加载。
注意:确保您没有在应用程序中使用要删除的密钥。
【讨论】:
【参考方案3】:这是来自ActionDispatch::Session的一些相关代码:
def [](key)
load_for_read!
@delegate[key.to_s]
end
private
def load_for_read!
load! if !loaded? && exists?
end
这意味着只要您通过 []
访问其键值,会话对象就会被加载。
【讨论】:
这是有道理的,但随后执行以下操作: session["session_id"] 应该始终返回一个值,因为如果会话尚未加载,它会在此时加载它,但情况并非如此对我来说。 你遇到的问题一开始真的很奇怪。您是否在一个空项目中尝试过您想要做的事情,所以您可以确定加载失败不是其他一些 gem 的原因。以及您使用的是什么版本(ruby 和 rails) Rails 3.2.11 和 ruby 1.9.3。会话实际上确实加载但不是我第一次尝试访问它时。我会尝试在没有 gems 的情况下进行测试,但无论如何我使用的东西很少:“therubyracer”、“couchrest”、“useragent”和“figaro”【参考方案4】:我不太明白你的问题。如果您需要用户注册或登录才能访问该站点,则应该没有问题。创建用户时,他的信息会立即存储在 cookie 中。例如:
用户控制器:(通过 users#new 完成注册)
def create
@user = User.new(params[:user])
if @user.save
cookies.permanent[:remember_token] = user.remember_token
redirect_to root_path, notice: "Thank you for registering!"
else
render :new
end
end
会话控制器:(通过会话#new 完成登录)
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
cookies.permanent[:remember_token] = user.remember_token
redirect_to root_path, notice: "Logged in."
else
flash.now.alert = "Email or password is incorrect."
render :new
end
end
【讨论】:
感谢您的回答,但我没有创建任何用户。我只想访问 Rails 会话 ID,但不能立即使用。 好吧,我想我误解了你的问题。【参考方案5】:所以问题可能归结为存储 session_id 的 cookie 在您尝试访问会话时尚未创建。
当你读取 session 对象时,Rails 会调用一个私有方法 session.load_for_read!
,但顾名思义,它只加载 session 进行读取,如果 session 根本不存在则不会实例化它。
另一方面,调用session.merge!()
(例如)会强制会话实例化。
【讨论】:
以上是关于加载该会话的力如何?的主要内容,如果未能解决你的问题,请参考以下文章
是否将Lazily提取的对象附加到Hibernate会话(由Hibernate支持的Spring Data)?