Sharing sessions between a rails3 app and a rails2 app. Rails 2 app crashes.

Hey all.

I have two apps. One is a rails3 app and the other is a rails 2 app. Using proxying I am routing actions in the myapp.com/foo to the rails2 app.

It almost works! I can set a session variable and a cookie variable on the first app (myapp.com) and then read them on the second app (myapp.com/foo).

It only works the first time though. If I go back to myapp.com and then revisit myapp.com/foo the rails2 application crashes with the error NameError (uninitialized constant ActiveSupport::HashWithIndifferentAccess):

This error is raised when any attempt to access the session variable is made.

I first thought it was because rails3 set a session['session_id'] and rails2 set a session[:session_id] so wrote some code to delete session['session_id'] but that didn't solve the problem.

The setup is pretty straightforward. They both use cookie sessions (for now). They both have the same key, secret and domain. nginex does the proxying.

So what is going on here? Any clues? Why does it work the first time but crash if you hit the back button and the forward button?

you should share some code here, there could be many reasons for that

Ok it's pretty simple.

In rails 2 app I have something like this.

Initializers session_store.rb

ActionController::Base.session_store = :cookie_store

ActionController::Base.session = {   :key => '_session_identifier',   :secret => secret

}

enviroment.rb

config.action_controller.session = {

          :domain => '.domain.name'

  }

In the rails 3 application I have this.

Rails.application.config.session_store :cookie_store, :key => '_session_identifier', :domain => ".domain.name" Rails.application.config.secret_token = secret Rails.application.config.cookie_secret = secret

in the rails3 app I set the variables like this

session['tim'] = 'This is a session variable' cookies['tim'] = 'This is a cookie variable'

in the rails2 app

@tim = session['tim'] @cookie = cookies['tim']

The steps needed to crash the rails 2 app.

go to domain.name      cookies and session variables are set go to subdomain name      cookie and session variable is read properly go back to domain name, reload go back to subdomain, reload     the applicaiton crashes

Well it looks like the core issue is that HashWithIndifferentAccess became ActiveSupport::HashWithIndifferentAccess in rails 3. The session is a serialized ruby object which somewhere is saying that it contains an instance of class ActiveSupport::HashWithIndifferentAccess and rails 2 is complaining that it doesn't know what that is. From what you've said I'm not sure why it works the first time. It could be that something on the second request is storing such a hash or that a development mode class loading oddity means that initially ActiveSupport::HashWithIndifferentAccess is able to find the top level class. You may be able to solve this by defining ActiveSupport::HashWithIndifferentAccess in your rails 2 app

Fred

Well it looks like the core issue is that HashWithIndifferentAccess became ActiveSupport::HashWithIndifferentAccess in rails 3. The session is a serialized ruby object which somewhere is saying that it contains an instance of class ActiveSupport::HashWithIndifferentAccess and rails 2 is complaining that it doesn't know what that is. From what you've said I'm not sure why it works the first time. It could be that something on the second request is storing such a hash or that a development mode class loading oddity means that initially ActiveSupport::HashWithIndifferentAccess is able to find the top level class. You may be able to solve this by defining ActiveSupport::HashWithIndifferentAccess in your rails 2 app

I'll give that a try and see if it works.

Another thing I noticed was that rails3 sets a 'session_id' and rails2 sets a :session_id

I don't know why they changed that.

I'll give that a try and see if it works.

Another thing I noticed was that rails3 sets a 'session_id' and rails2 sets a :session_id

Just to follow up on this...

Your workaround worked but it only went so far. Now I am getting this error.

Session contains objects whose class definition isn\'t available. Remember to require the classes for all objects kept in the session. (Original exception: #{const_error.message} [#{const_error.class}])

I am not going to chase this down. Who knows what object it's complaining about. I think I am just going to set a cookie and track it on the other app. That part seems to be working OK.

I hope this saves somebody lots of work.

Tim

Session contains objects whose class definition isn\'t available. Remember to require the classes for all objects kept in the session. (Original exception: #{const_error.message} [#{const_error.class}])

This is because the class definition for flash notifications changed. You can see this discussed at

If you can stop using flash notifications, that is one "solution". We're trying to figure out a better fix.

The suggestion to use flash.now[:notice] is only going to work if there is no redirect between setting the message and rendering it.

I think the best hack, although ugly, will be to make rails2 and rails3 both aware of the class that the other one uses for flashes. They don't need to deal with it, just have a class definition.

Brad

Just an update to this. I was trying to do the same thing, specifically have a Rails3 app read some state from the session set by Rails2. I got it working by doing what Brad M. suggested, making Rails3 aware of the Rails2 class that was missing.

I included the definition of ActionController::Flash in a file that got loaded at startup. It was necessary to comment out two calls to alias_chain_method right at the start of the code. It appears this works for Rails3 to read what Rails2 has put into the session, and that's all I need to do.

I'm not going to push it any further but suspect this might provide others with a migration strategy.