Skip to content

Commit d2d7c38

Browse files
committed
Allow ActiveRecordStore.session_class to be evaluated lazily
Prevents Active Record from being loaded early in an initializer (where the session_class is being set. This can slow down application boot time.
1 parent 734c38f commit d2d7c38

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

lib/action_dispatch/session/active_record_store.rb

+26-5
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ module Session
3939
# feature-packed Active Record or a bare-metal high-performance SQL
4040
# store, by setting
4141
#
42-
# ActionDispatch::Session::ActiveRecordStore.session_class = MySessionClass
42+
# ActionDispatch::Session::ActiveRecordStore.session_class = "MySessionClass"
4343
#
44-
# You must implement these methods:
44+
# The class may optionally be passed as a string or proc to prevent autoloading
45+
# code early. You must implement these methods:
4546
#
4647
# self.find_by_session_id(session_id)
4748
# initialize(hash_of_session_id_and_data, options_hash = {})
@@ -53,13 +54,33 @@ module Session
5354
# The example SqlBypass class is a generic SQL session store. You may
5455
# use it as a basis for high-performance database-specific stores.
5556
class ActiveRecordStore < ActionDispatch::Session::AbstractSecureStore
56-
# The class used for session storage. Defaults to
57-
# ActiveRecord::SessionStore::Session
58-
class_attribute :session_class
57+
class << self
58+
# The class used for session storage. Defaults to
59+
# ActiveRecord::SessionStore::Session
60+
def session_class
61+
@session_class_instance ||= case @session_class
62+
when Proc
63+
@session_class.call
64+
when String
65+
@session_class.constantize
66+
else
67+
@session_class
68+
end
69+
end
70+
71+
def session_class=(session_class)
72+
@session_class_instance = nil
73+
@session_class = session_class
74+
end
75+
end
5976

6077
SESSION_RECORD_KEY = 'rack.session.record'
6178
ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS
6279

80+
def session_class
81+
self.class.session_class
82+
end
83+
6384
private
6485
def get_session(request, sid)
6586
logger.silence do

test/session_store_test.rb

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
require "helper"
2+
require "action_dispatch/session/active_record_store"
3+
4+
module ActionDispatch
5+
module Session
6+
class ActiveRecordStoreTest < ActiveSupport::TestCase
7+
8+
class Session < ActiveRecord::SessionStore::Session; end
9+
10+
def test_session_class_as_string
11+
with_session_class("ActionDispatch::Session::ActiveRecordStoreTest::Session") do
12+
assert_equal(Session, ActiveRecordStore.session_class)
13+
end
14+
end
15+
16+
def test_session_class_as_proc
17+
with_session_class(proc { Session }) do
18+
assert_equal(Session, ActiveRecordStore.session_class)
19+
end
20+
end
21+
22+
def test_session_class_as_class
23+
with_session_class(Session) do
24+
assert_equal(Session, ActiveRecordStore.session_class)
25+
end
26+
end
27+
28+
private
29+
30+
def with_session_class(klass)
31+
old_klass = ActiveRecordStore.session_class
32+
ActiveRecordStore.session_class = klass
33+
yield
34+
ensure
35+
ActiveRecordStore.session_class = old_klass
36+
end
37+
end
38+
end
39+
end

0 commit comments

Comments
 (0)