Replacing ActiveRecordStore::Session with a custom model

Has anyone managed to replace ActiveRecordStore::Session with their own model?

In the source (http://dev.rubyonrails.org/browser/trunk/actionpack/lib/ action_controller/session/active_record_store.rb) it says you can override the default by setting CGI::Session::ActiveRecordStore.session_class = MySessionClass

I have tried doing this in a number of ways but I get all kinds of weird errors, as varied as the methods I've tried.

Before you shoot me down for trying to do something I shouldn't let me explain why I want to do this.

I'd like a session model that looks something like:

class Session < ActiveRecord::Base   has_many :product_viewings, :dependent => :destroy   has_many :products, :through => :product_viewings, :limit => 10, :include => :image

  belongs_to :order   belongs_to :user end

In my controller I would like to do something like

session.model.user = @user

and

@recently_viewed_products = session.model.products

Because I cannot replace ActiveRecordStore::Session with my session class above I have to do instead:

session.model.user_id = @user.id

and

@recently_viewed_products = Session.find_by_session_id(session.session_id).products

I don't think it's unreasonable to want to treat session.model as a first class ActiveRecord model, anything else just seems a bit half- baked.

Any ideas on how I could make this happen would be greatly appreciated.

Paul Odeon

Ok I finally nailed it...

I found that using CGI::Session::ActiveRecordStore.session_class = Session worked in production mode but not in dev, I could also make it work in dev but only by setting config.cache_classes = true

In dev it would work on the first page load but crash with a stack too deep error on the second and subsequent attempt.

Definitely a dependencies issue then...

All the classes are reloaded on every request, including our custom Session class. However, CGI::Session::ActiveRecordStore.session_class is only set on application initialization, and the session_class variable is left holding a stale version of the Session class. What we need is a way to update ActiveRecordStore with a fresh Session class after every request, the magic line of code to do that is at the end of this post.

So to create your own session model with all the ActiveRecord goodness follow these steps:

1. config/initializers/session.rb CGI::Session::ActiveRecordStore.session_class = Session

2. app/models/session.rb class Session < CGI::Session::ActiveRecordStore::Session   has_many :product_viewings, :dependent => :destroy   has_many :products, :through => :product_viewings, :limit => 10, :include => :image   #Or whatever ActiveRecord stuff you like end

3. config/environment.rb Rails::Initializer.run do |config|   config.action_controller.session_store = :active_record_store   config.to_prepare { CGI::Session::ActiveRecordStore.session_class = Session if ENV['RAILS_ENV'] == 'development' } # This is the one end

config.to_prepare executes the block it is passed before each request in rails. In it, we pass the freshly reloaded class to the Session store but only in dev.

I hope this helps someone struggling with the same problem...

Cheers

One small glitch with the above solution

Any of the script/* and rake scripts seem to fail with some sort of dependency error

This is a bug (http://dev.rubyonrails.org/ticket/10520) and is apparently fixed in 2.0.2, although that's what I am using and I still get the error.

As described in the link above, I put the following above the config.to_prepare block and everything worked perfectly.

  #fixes rails bug described here: http://dev.rubyonrails.org/ticket/10520   #this monkey patch should be removed when problem is fixed in rails     module Rails       class Configuration         def to_prepare(&callback)           after_initialize do             require 'dispatcher' unless defined?(::Dispatcher)             Dispatcher.to_prepare(&callback)           end         end       end     end