diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index a79c2a67a0..e1444c28c9 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -94,6 +94,19 @@ module ActionDispatch autoload :CookieStore, "action_dispatch/middleware/session/cookie_store" autoload :MemCacheStore, "action_dispatch/middleware/session/mem_cache_store" autoload :CacheStore, "action_dispatch/middleware/session/cache_store" + + def self.resolve_store(session_store) # :nodoc: + self.const_get(session_store.to_s.camelize) + rescue NameError + raise <<~ERROR + Unable to resolve session store #{session_store.inspect}. + + #{session_store.inspect} resolves to ActionDispatch::Session::#{session_store.to_s.camelize}, + but that class is undefined. + + Is #{session_store.inspect} spelled correctly, and are any necessary gems installed? + ERROR + end end mattr_accessor :test_app diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 86a286fed4..bf81a2d752 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -378,8 +378,11 @@ Your application has a session for each user in which you can store small amount * [`ActionDispatch::Session::CookieStore`][] - Stores everything on the client. * [`ActionDispatch::Session::CacheStore`][] - Stores the data in the Rails cache. -* `ActionDispatch::Session::ActiveRecordStore` - Stores the data in a database using Active Record (requires the `activerecord-session_store` gem). * [`ActionDispatch::Session::MemCacheStore`][] - Stores the data in a memcached cluster (this is a legacy implementation; consider using `CacheStore` instead). +* [`ActionDispatch::Session::ActiveRecordStore`][activerecord-session_store] - + Stores the data in a database using Active Record (requires the + [`activerecord-session_store`][activerecord-session_store] gem) +* A custom store or a store provided by a third party gem All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure). @@ -394,12 +397,12 @@ Read more about session storage in the [Security Guide](security.html). If you need a different session storage mechanism, you can change it in an initializer: ```ruby -# Use the database for sessions instead of the cookie-based default, -# which shouldn't be used to store highly confidential information -# (create the session table with "rails g active_record:session_migration") -# Rails.application.config.session_store :active_record_store +Rails.application.config.session_store :cache_store ``` +See [`config.session_store`](configuring.html#config-session-store) in the +configuration guide for more information. + Rails sets up a session key (the name of the cookie) when signing the session data. These can also be changed in an initializer: ```ruby @@ -430,6 +433,8 @@ NOTE: Changing the secret_key_base when using the `CookieStore` will invalidate [`ActionDispatch::Session::CookieStore`]: https://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html [`ActionDispatch::Session::CacheStore`]: https://api.rubyonrails.org/classes/ActionDispatch/Session/CacheStore.html [`ActionDispatch::Session::MemCacheStore`]: https://api.rubyonrails.org/classes/ActionDispatch/Session/MemCacheStore.html +[activerecord-session_store]: https://github.com/rails/activerecord-session_store + ### Accessing the Session diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 952c1b8080..b5f2a6acb5 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -428,7 +428,7 @@ module Rails # Specifies what class to use to store the session. Possible values # are +:cache_store+, +:cookie_store+, +:mem_cache_store+, a custom - # store, or +:disabled+. +:disabled+ tells Rails not to deal with + # store, or +:disabled+. +:disabled+ tells \Rails not to deal with # sessions. # # Additional options will be set as +session_options+: @@ -443,25 +443,14 @@ module Rails # config.session_store :my_custom_store def session_store(new_session_store = nil, **options) if new_session_store - if new_session_store == :active_record_store - begin - ActionDispatch::Session::ActiveRecordStore - rescue NameError - raise "`ActiveRecord::SessionStore` is extracted out of Rails into a gem. " \ - "Please add `activerecord-session_store` to your Gemfile to use it." - end - end - @session_store = new_session_store @session_options = options || {} else case @session_store when :disabled nil - when :active_record_store - ActionDispatch::Session::ActiveRecordStore when Symbol - ActionDispatch::Session.const_get(@session_store.to_s.camelize) + ActionDispatch::Session.resolve_store(@session_store) else @session_store end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index b543ab27d2..cd6b728964 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1647,13 +1647,14 @@ module ApplicationTests ActionDispatch::Session.send :remove_const, :ActiveRecordStore end - test "config.session_store with :active_record_store without activerecord-session_store gem" do + test "config.session_store with unknown store raises helpful error" do e = assert_raise RuntimeError do make_basic_app do |application| - application.config.session_store :active_record_store + application.config.session_store :unknown_store end end - assert_match(/activerecord-session_store/, e.message) + + assert_match(/Unable to resolve session store :unknown_store/, e.message) end test "default session store initializer does not overwrite the user defined session store even if it is disabled" do