'How force that session is loaded?

I'm working on an application that needs to use session id information. My session is stored in cookies. The problem I have is that my session is not immediately available to the controller when a user comes to the site for the first time. I think I may be missing something about how sessions are initialized in Rails. But I'm positve about the fact that the session is not loaded because this is the output of session.inspect:

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

Here is how to reproduce the problem with Rails 3.2.11 and ruby 1.9.3:

Create a new application with a test controller:

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

Try to get the session id in that controller:

class TestController < ApplicationController
  def index
    puts session[:session_id]
    puts session.inspect
  end
end

Add the needed routes:

MyApp::Application.routes.draw do
  resources :test
end

Then access the application and see what it does:

rails server

got to: http://localhost:3000/test

That is the output in the console:

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

Then again http://localhost:3000/test and this time we have a session:

400706c0b3d95a5a1e56521e455075ac
{"session_id"=>"400706c0b3d95a5a1e56521e455075ac", "_csrf_token"=>"Euaign8Ptpj/o/8/ucBFMgxGtiH7goKxkxeGctumyGQ="}


Solution 1:[1]

I agree with @joscas answer but instead of writing a value, I'd delete it as to not have redundant data.

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

The session is loaded this way too.

Note: Make sure you don't use the key to be deleted in your application.

Solution 2:[2]

Here's some relevant code from ActionDispatch::Session:

 def [](key)
    load_for_read!
    @delegate[key.to_s]
  end

  private

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

Which implies that the session object will be loaded as soon as you access any value by its key via [].

Solution 3:[3]

I don't really understand your question. If you require a user to register or sign in before being able to access the site there should be no problem. When creating a user his information is immediately stored in a cookie. For example:

User controller: (registering is done through 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

Sessions controller: (signing in is done through sessions#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

Solution 4:[4]

So the problem probably boils down to the fact that the cookie that stores session_id wasn't created yet at the point where you tried to access the session.

When you read session object, Rails calls a private method session.load_for_read!, but, as its name suggests, it only loads session for reading and doesn't instantiates the session if it simply doesn't exist.

On the other hand, calling session.merge!({}) (for example) forces session instantiation.

Solution 5:[5]

Yo! @zetetic's answer above made me realize that we can just do

session.send(:load!)

and it'll load the session ?.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lazarus Lazaridis
Solution 2 zetetic
Solution 3 Peter de Ridder
Solution 4 Alexis
Solution 5 Jon Sullivan