如何强制加载该会话?

问题描述 投票:0回答:7

我正在开发一个需要使用会话 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="}
ruby-on-rails ruby-on-rails-3 session ruby-on-rails-3.2
7个回答
24
投票

我找到了一种强制会话初始化的方法。访问会话显然不会强制初始化,但写入会话会强制初始化。我现在在控制器中所做的是:

class MyController < ApplicationController
  protect_from_forgery
  def index
    session["init"] = true
    do_stuff
  end
end

我仍然不确定这是否应该被视为 Rails 中的正常行为。在我看来,必须写入会话来强制初始化是不正确的。读书应该足够了。


9
投票

我同意@joscas的答案,但我不会写一个值,而是将其删除以避免冗余数据。

class MyController < ApplicationController
  protect_from_forgery
  def index
    session.delete 'init'
    do_stuff
  end
end

会话也是这样加载的。

注意: 确保您没有在应用程序中使用要删除的密钥。


7
投票

这是来自 ActionDispatch::Session:

的一些相关代码
 def [](key)
    load_for_read!
    @delegate[key.to_s]
  end

  private

  def load_for_read!
    load! if !loaded? && exists?
  end

这意味着只要您通过

[]
通过其键访问任何值,会话对象就会被加载。


1
投票

哟! @zetetic 上面的回答让我意识到我们可以这样做

session.send(:load!)

它将加载会话 🙂.


0
投票

我不太明白你的问题。如果您要求用户先注册或登录才能访问该网站,应该没有问题。创建用户时,他的信息会立即存储在 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

会话控制器:(通过session#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

0
投票

所以问题可能归结为这样一个事实:在您尝试访问会话时,存储 session_id 的 cookie 尚未创建。

当您读取会话对象时,Rails 会调用一个私有方法

session.load_for_read!
,但是,正如其名称所暗示的,它仅加载会话以供读取,并且如果会话不存在,则不会实例化该会话。

另一方面,调用

session.merge!({})
(例如)会强制会话实例化。


0
投票

由于会话是延迟加载的对象,因此您只需开始访问会话对象即可

pry> session

...未加载

pry> session["session_id"] # .....
© www.soinside.com 2019 - 2024. All rights reserved.