轨道上的红宝石 - 加载该会话的强制力



我正在开发一个需要使用会话ID信息的应用程序。我的会话存储在 Cookie 中。我遇到的问题是,当用户第一次访问该站点时,我的会话不会立即可供控制器使用。我想我可能错过了一些关于如何在 Rails 中初始化会话的内容。但我对会话未加载的事实持积极态度,因为这是session.inspect的输出:

#<Rack::Session::Abstract::SessionHash:0x15cb970 not yet loaded>

以下是重现Rails 3.2.11ruby 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="}

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

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

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

我同意@joscas答案,但不是写一个值,而是删除它,因为没有冗余数据。

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

会话也是以这种方式加载的。

注意:请确保不要在应用程序中使用要删除的密钥。

以下是来自ActionDispatch::Session的一些相关代码:

 def [](key)
    load_for_read!
    @delegate[key.to_s]
  end
  private
  def load_for_read!
    load! if !loaded? && exists?
  end

这意味着一旦您通过 [] 键访问任何值,会话对象就会被加载。

我真的不明白你的问题。如果您要求用户在能够访问网站之前注册或登录,则应该没有问题。创建用户时,他的信息会立即存储在cookie中。例如:

用户

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

控制器:(通过会话#新建完成登录)

 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

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

当你读取会话对象时,Rails 调用一个私有方法session.load_for_read!,但顾名思义,它只加载会话进行读取,如果会话根本不存在,则不会实例化会话。

另一方面,调用session.merge!({})(例如)会强制会话实例化。

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

session.send(:load!)

它将加载会话🙂.

相关内容

  • 没有找到相关文章

最新更新