From 0ffe19056c8e8b2f9ae9d487b896cad2ce9387ad Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Wed, 15 Aug 2012 01:22:50 -0400 Subject: [PATCH] Extract ActiveRecord::SessionStore from Rails This functionality will be available from gem `active_record-session_store` instead. --- actionpack/CHANGELOG.md | 4 + actionpack/lib/action_controller/base.rb | 9 - .../activerecord/active_record_store_test.rb | 288 -------------- activerecord/CHANGELOG.md | 3 + activerecord/lib/active_record.rb | 11 - .../lib/active_record/railties/databases.rake | 15 - .../lib/active_record/session_store.rb | 365 ------------------ .../session_migration_generator.rb | 24 -- .../session_migration/templates/migration.rb | 12 - .../test/cases/session_store/session_test.rb | 81 ---- .../cases/session_store/sql_bypass_test.rb | 75 ---- .../config/initializers/session_store.rb | 5 - .../active_support_core_extensions.textile | 10 +- .../lib/rails/application/configuration.rb | 2 - railties/lib/rails/generators.rb | 1 - .../config/initializers/session_store.rb.tt | 5 - .../initializers/frameworks_test.rb | 20 - .../session_migration_generator_test.rb | 27 -- 18 files changed, 10 insertions(+), 947 deletions(-) delete mode 100644 actionpack/test/activerecord/active_record_store_test.rb delete mode 100644 activerecord/lib/active_record/session_store.rb delete mode 100644 activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb delete mode 100644 activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb delete mode 100644 activerecord/test/cases/session_store/session_test.rb delete mode 100644 activerecord/test/cases/session_store/sql_bypass_test.rb delete mode 100644 railties/test/generators/session_migration_generator_test.rb diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 1445cf43f6..4aaa9bcd23 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,9 @@ ## Rails 4.0.0 (unreleased) ## +* `ActiveRecord::SessionStore` is extracted out of Rails into a gem `activerecord-session_store`. + Setting `config.session_store` to `:active_record_store` will no longer work and will break + if the `activerecord-session_store` gem isn't available. *Prem Sichanugrist* + * Fix select_tag when option_tags is nil. Fixes #7404. diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 71425cd542..f829f5e8a2 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -88,15 +88,6 @@ module ActionController # # Do not put secret information in cookie-based sessions! # - # Other options for session storage: - # - # * ActiveRecord::SessionStore - Sessions are stored in your database, which works better than PStore with multiple app servers and, - # unlike CookieStore, hides your session contents from the user. To use ActiveRecord::SessionStore, set - # - # MyApplication::Application.config.session_store :active_record_store - # - # in your config/initializers/session_store.rb and run script/rails g session_migration. - # # == Responses # # Each action results in a response, which holds the headers and document to be sent to the user's browser. The actual response diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb deleted file mode 100644 index 275f25f597..0000000000 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ /dev/null @@ -1,288 +0,0 @@ -require 'active_record_unit' - -class ActiveRecordStoreTest < ActionDispatch::IntegrationTest - class TestController < ActionController::Base - def no_session_access - head :ok - end - - def set_session_value - raise "missing session!" unless session - session[:foo] = params[:foo] || "bar" - head :ok - end - - def get_session_value - render :text => "foo: #{session[:foo].inspect}" - end - - def get_session_id - render :text => "#{request.session_options[:id]}" - end - - def call_reset_session - session[:foo] - reset_session - reset_session if params[:twice] - session[:foo] = "baz" - head :ok - end - - def renew - env["rack.session.options"][:renew] = true - session[:foo] = "baz" - head :ok - end - end - - def setup - ActiveRecord::SessionStore.session_class.create_table! - end - - def teardown - ActiveRecord::SessionStore.session_class.drop_table! - end - - %w{ session sql_bypass }.each do |class_name| - define_method("test_setting_and_getting_session_value_with_#{class_name}_store") do - with_store class_name do - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - - get '/get_session_value' - assert_response :success - assert_equal 'foo: "bar"', response.body - - get '/set_session_value', :foo => "baz" - assert_response :success - assert cookies['_session_id'] - - get '/get_session_value' - assert_response :success - assert_equal 'foo: "baz"', response.body - - get '/call_reset_session' - assert_response :success - assert_not_equal [], headers['Set-Cookie'] - end - end - end - - define_method("test_renewing_with_#{class_name}_store") do - with_store class_name do - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - - get '/renew' - assert_response :success - assert_not_equal [], headers['Set-Cookie'] - end - end - end - end - - def test_getting_nil_session_value - with_test_route_set do - get '/get_session_value' - assert_response :success - assert_equal 'foo: nil', response.body - end - end - - def test_calling_reset_session_twice_does_not_raise_errors - with_test_route_set do - get '/call_reset_session', :twice => "true" - assert_response :success - - get '/get_session_value' - assert_response :success - assert_equal 'foo: "baz"', response.body - end - end - - def test_setting_session_value_after_session_reset - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - session_id = cookies['_session_id'] - - get '/call_reset_session' - assert_response :success - assert_not_equal [], headers['Set-Cookie'] - - get '/get_session_value' - assert_response :success - assert_equal 'foo: "baz"', response.body - - get '/get_session_id' - assert_response :success - assert_not_equal session_id, response.body - end - end - - def test_getting_session_value_after_session_reset - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - session_cookie = cookies.send(:hash_for)['_session_id'] - - get '/call_reset_session' - assert_response :success - assert_not_equal [], headers['Set-Cookie'] - - cookies << session_cookie # replace our new session_id with our old, pre-reset session_id - - get '/get_session_value' - assert_response :success - assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from the database" - end - end - - def test_getting_from_nonexistent_session - with_test_route_set do - get '/get_session_value' - assert_response :success - assert_equal 'foo: nil', response.body - assert_nil cookies['_session_id'], "should only create session on write, not read" - end - end - - def test_getting_session_id - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - session_id = cookies['_session_id'] - - get '/get_session_id' - assert_response :success - assert_equal session_id, response.body, "should be able to read session id without accessing the session hash" - end - end - - def test_doesnt_write_session_cookie_if_session_id_is_already_exists - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - - get '/get_session_value' - assert_response :success - assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists" - end - end - - def test_prevents_session_fixation - with_test_route_set do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - - get '/get_session_value' - assert_response :success - assert_equal 'foo: "bar"', response.body - session_id = cookies['_session_id'] - assert session_id - - reset! - - get '/get_session_value', :_session_id => session_id - assert_response :success - assert_equal 'foo: nil', response.body - assert_not_equal session_id, cookies['_session_id'] - end - end - - def test_allows_session_fixation - with_test_route_set(:cookie_only => false) do - get '/set_session_value' - assert_response :success - assert cookies['_session_id'] - - get '/get_session_value' - assert_response :success - assert_equal 'foo: "bar"', response.body - session_id = cookies['_session_id'] - assert session_id - - reset! - - get '/set_session_value', :_session_id => session_id, :foo => "baz" - assert_response :success - assert_equal session_id, cookies['_session_id'] - - get '/get_session_value', :_session_id => session_id - assert_response :success - assert_equal 'foo: "baz"', response.body - assert_equal session_id, cookies['_session_id'] - end - end - - def test_incoming_invalid_session_id_via_cookie_should_be_ignored - with_test_route_set do - open_session do |sess| - sess.cookies['_session_id'] = 'INVALID' - - sess.get '/set_session_value' - new_session_id = sess.cookies['_session_id'] - assert_not_equal 'INVALID', new_session_id - - sess.get '/get_session_value' - new_session_id_2 = sess.cookies['_session_id'] - assert_equal new_session_id, new_session_id_2 - end - end - end - - def test_incoming_invalid_session_id_via_parameter_should_be_ignored - with_test_route_set(:cookie_only => false) do - open_session do |sess| - sess.get '/set_session_value', :_session_id => 'INVALID' - new_session_id = sess.cookies['_session_id'] - assert_not_equal 'INVALID', new_session_id - - sess.get '/get_session_value' - new_session_id_2 = sess.cookies['_session_id'] - assert_equal new_session_id, new_session_id_2 - end - end - end - - def test_session_store_with_all_domains - with_test_route_set(:domain => :all) do - get '/set_session_value' - assert_response :success - end - end - - private - - def with_test_route_set(options = {}) - with_routing do |set| - set.draw do - get ':action', :to => 'active_record_store_test/test' - end - - @app = self.class.build_app(set) do |middleware| - middleware.use ActiveRecord::SessionStore, options.reverse_merge(:key => '_session_id') - middleware.delete "ActionDispatch::ShowExceptions" - end - - yield - end - end - - def with_store(class_name) - session_class, ActiveRecord::SessionStore.session_class = - ActiveRecord::SessionStore.session_class, "ActiveRecord::SessionStore::#{class_name.camelize}".constantize - yield - ensure - ActiveRecord::SessionStore.session_class = session_class - end -end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index c5ef39b9d2..18b10f1d81 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,8 @@ ## Rails 4.0.0 (unreleased) ## +* ActiveRecord::SessionStore has been extracted from Active Record as `activerecord-session_store` + gem. Please read the `README.md` file on the gem for the usage. *Prem Sichanugrist* + * Fix `reset_counters` when there are multiple `belongs_to` association with the same foreign key and one of them have a counter cache. Fixes #5200. diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index fa94f6a941..1675127ab0 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -53,17 +53,6 @@ module ActiveRecord autoload :ReadonlyAttributes autoload :Reflection autoload :Sanitization - - # ActiveRecord::SessionStore depends on the abstract store in Action Pack. - # Eager loading this class would break client code that eager loads Active - # Record standalone. - # - # Note that the Rails application generator creates an initializer specific - # for setting the session store. Thus, albeit in theory this autoload would - # not be thread-safe, in practice it is because if the application uses this - # session store its autoload happens at boot time. - autoload :SessionStore - autoload :Schema autoload :SchemaDumper autoload :SchemaMigration diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 4e5ec4f739..ae24542521 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -408,21 +408,6 @@ db_namespace = namespace :db do end end end - - namespace :sessions do - # desc "Creates a sessions migration for use with ActiveRecord::SessionStore" - task :create => [:environment, :load_config] do - raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations? - Rails.application.load_generators - require 'rails/generators/rails/session_migration/session_migration_generator' - Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ] - end - - # desc "Clear the sessions table" - task :clear => [:environment, :load_config] do - ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::SessionStore::Session.table_name}" - end - end end namespace :railties do diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb deleted file mode 100644 index 58e1dab508..0000000000 --- a/activerecord/lib/active_record/session_store.rb +++ /dev/null @@ -1,365 +0,0 @@ -require 'action_dispatch/middleware/session/abstract_store' - -module ActiveRecord - # = Active Record Session Store - # - # A session store backed by an Active Record class. A default class is - # provided, but any object duck-typing to an Active Record Session class - # with text +session_id+ and +data+ attributes is sufficient. - # - # The default assumes a +sessions+ tables with columns: - # +id+ (numeric primary key), - # +session_id+ (string, usually varchar; maximum length is 255), and - # +data+ (text or longtext; careful if your session data exceeds 65KB). - # - # The +session_id+ column should always be indexed for speedy lookups. - # Session data is marshaled to the +data+ column in Base64 format. - # If the data you write is larger than the column's size limit, - # ActionController::SessionOverflowError will be raised. - # - # You may configure the table name, primary key, and data column. - # For example, at the end of config/application.rb: - # - # ActiveRecord::SessionStore::Session.table_name = 'legacy_session_table' - # ActiveRecord::SessionStore::Session.primary_key = 'session_id' - # ActiveRecord::SessionStore::Session.data_column_name = 'legacy_session_data' - # - # Note that setting the primary key to the +session_id+ frees you from - # having a separate +id+ column if you don't want it. However, you must - # set session.model.id = session.session_id by hand! A before filter - # on ApplicationController is a good place. - # - # Since the default class is a simple Active Record, you get timestamps - # for free if you add +created_at+ and +updated_at+ datetime columns to - # the +sessions+ table, making periodic session expiration a snap. - # - # You may provide your own session class implementation, whether a - # feature-packed Active Record or a bare-metal high-performance SQL - # store, by setting - # - # ActiveRecord::SessionStore.session_class = MySessionClass - # - # You must implement these methods: - # - # self.find_by_session_id(session_id) - # initialize(hash_of_session_id_and_data, options_hash = {}) - # attr_reader :session_id - # attr_accessor :data - # save - # destroy - # - # The example SqlBypass class is a generic SQL session store. You may - # use it as a basis for high-performance database-specific stores. - class SessionStore < ActionDispatch::Session::AbstractStore - module ClassMethods # :nodoc: - def marshal(data) - ::Base64.encode64(Marshal.dump(data)) if data - end - - def unmarshal(data) - Marshal.load(::Base64.decode64(data)) if data - end - - def drop_table! - connection.schema_cache.clear_table_cache!(table_name) - connection.drop_table table_name - end - - def create_table! - connection.schema_cache.clear_table_cache!(table_name) - connection.create_table(table_name) do |t| - t.string session_id_column, :limit => 255 - t.text data_column_name - end - connection.add_index table_name, session_id_column, :unique => true - end - end - - # The default Active Record class. - class Session < ActiveRecord::Base - extend ClassMethods - - ## - # :singleton-method: - # Customizable data column name. Defaults to 'data'. - cattr_accessor :data_column_name - self.data_column_name = 'data' - - attr_accessible :session_id, :data, :marshaled_data - - before_save :marshal_data! - before_save :raise_on_session_data_overflow! - - class << self - def data_column_size_limit - @data_column_size_limit ||= columns_hash[data_column_name].limit - end - - # Hook to set up sessid compatibility. - def find_by_session_id(session_id) - setup_sessid_compatibility! - find_by_session_id(session_id) - end - - private - def session_id_column - 'session_id' - end - - # Compatibility with tables using sessid instead of session_id. - def setup_sessid_compatibility! - # Reset column info since it may be stale. - reset_column_information - if columns_hash['sessid'] - def self.find_by_session_id(*args) - find_by_sessid(*args) - end - - define_method(:session_id) { sessid } - define_method(:session_id=) { |session_id| self.sessid = session_id } - else - class << self; remove_possible_method :find_by_session_id; end - - def self.find_by_session_id(session_id) - where(session_id: session_id).first - end - end - end - end - - def initialize(attributes = nil, options = {}) - @data = nil - super - end - - # Lazy-unmarshal session state. - def data - @data ||= self.class.unmarshal(read_attribute(@@data_column_name)) || {} - end - - attr_writer :data - - # Has the session been loaded yet? - def loaded? - @data - end - - private - def marshal_data! - return false unless loaded? - write_attribute(@@data_column_name, self.class.marshal(data)) - end - - # Ensures that the data about to be stored in the database is not - # larger than the data storage column. Raises - # ActionController::SessionOverflowError. - def raise_on_session_data_overflow! - return false unless loaded? - limit = self.class.data_column_size_limit - if limit and read_attribute(@@data_column_name).size > limit - raise ActionController::SessionOverflowError - end - end - end - - # A barebones session store which duck-types with the default session - # store but bypasses Active Record and issues SQL directly. This is - # an example session model class meant as a basis for your own classes. - # - # The database connection, table name, and session id and data columns - # are configurable class attributes. Marshaling and unmarshaling - # are implemented as class methods that you may override. By default, - # marshaling data is - # - # ::Base64.encode64(Marshal.dump(data)) - # - # and unmarshaling data is - # - # Marshal.load(::Base64.decode64(data)) - # - # This marshaling behavior is intended to store the widest range of - # binary session data in a +text+ column. For higher performance, - # store in a +blob+ column instead and forgo the Base64 encoding. - class SqlBypass - extend ClassMethods - - ## - # :singleton-method: - # The table name defaults to 'sessions'. - cattr_accessor :table_name - @@table_name = 'sessions' - - ## - # :singleton-method: - # The session id field defaults to 'session_id'. - cattr_accessor :session_id_column - @@session_id_column = 'session_id' - - ## - # :singleton-method: - # The data field defaults to 'data'. - cattr_accessor :data_column - @@data_column = 'data' - - class << self - alias :data_column_name :data_column - - # Use the ActiveRecord::Base.connection by default. - attr_writer :connection - - # Use the ActiveRecord::Base.connection_pool by default. - attr_writer :connection_pool - - def connection - @connection ||= ActiveRecord::Base.connection - end - - def connection_pool - @connection_pool ||= ActiveRecord::Base.connection_pool - end - - # Look up a session by id and unmarshal its data if found. - def find_by_session_id(session_id) - if record = connection.select_one("SELECT #{connection.quote_column_name(data_column)} AS data FROM #{@@table_name} WHERE #{connection.quote_column_name(@@session_id_column)}=#{connection.quote(session_id.to_s)}") - new(:session_id => session_id, :marshaled_data => record['data']) - end - end - end - - delegate :connection, :connection=, :connection_pool, :connection_pool=, :to => self - - attr_reader :session_id, :new_record - alias :new_record? :new_record - - attr_writer :data - - # Look for normal and marshaled data, self.find_by_session_id's way of - # telling us to postpone unmarshaling until the data is requested. - # We need to handle a normal data attribute in case of a new record. - def initialize(attributes) - @session_id = attributes[:session_id] - @data = attributes[:data] - @marshaled_data = attributes[:marshaled_data] - @new_record = @marshaled_data.nil? - end - - # Returns true if the record is persisted, i.e. it's not a new record - def persisted? - !@new_record - end - - # Lazy-unmarshal session state. - def data - unless @data - if @marshaled_data - @data, @marshaled_data = self.class.unmarshal(@marshaled_data) || {}, nil - else - @data = {} - end - end - @data - end - - def loaded? - @data - end - - def save - return false unless loaded? - marshaled_data = self.class.marshal(data) - connect = connection - - if @new_record - @new_record = false - connect.update <<-end_sql, 'Create session' - INSERT INTO #{table_name} ( - #{connect.quote_column_name(session_id_column)}, - #{connect.quote_column_name(data_column)} ) - VALUES ( - #{connect.quote(session_id)}, - #{connect.quote(marshaled_data)} ) - end_sql - else - connect.update <<-end_sql, 'Update session' - UPDATE #{table_name} - SET #{connect.quote_column_name(data_column)}=#{connect.quote(marshaled_data)} - WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id)} - end_sql - end - end - - def destroy - return if @new_record - - connect = connection - connect.delete <<-end_sql, 'Destroy session' - DELETE FROM #{table_name} - WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id.to_s)} - end_sql - end - end - - # The class used for session storage. Defaults to - # ActiveRecord::SessionStore::Session - cattr_accessor :session_class - self.session_class = Session - - SESSION_RECORD_KEY = 'rack.session.record' - ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY - - private - def get_session(env, sid) - Base.silence do - unless sid and session = @@session_class.find_by_session_id(sid) - # If the sid was nil or if there is no pre-existing session under the sid, - # force the generation of a new sid and associate a new session associated with the new sid - sid = generate_sid - session = @@session_class.new(:session_id => sid, :data => {}) - end - env[SESSION_RECORD_KEY] = session - [sid, session.data] - end - end - - def set_session(env, sid, session_data, options) - Base.silence do - record = get_session_model(env, sid) - record.data = session_data - return false unless record.save - - session_data = record.data - if session_data && session_data.respond_to?(:each_value) - session_data.each_value do |obj| - obj.clear_association_cache if obj.respond_to?(:clear_association_cache) - end - end - end - - sid - end - - def destroy_session(env, session_id, options) - if sid = current_session_id(env) - Base.silence do - get_session_model(env, sid).destroy - env[SESSION_RECORD_KEY] = nil - end - end - - generate_sid unless options[:drop] - end - - def get_session_model(env, sid) - if env[ENV_SESSION_OPTIONS_KEY][:id].nil? - env[SESSION_RECORD_KEY] = find_session(sid) - else - env[SESSION_RECORD_KEY] ||= find_session(sid) - end - end - - def find_session(id) - @@session_class.find_by_session_id(id) || - @@session_class.new(:session_id => id, :data => {}) - end - end -end diff --git a/activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb b/activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb deleted file mode 100644 index 75aee4f408..0000000000 --- a/activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'rails/generators/active_record' - -module ActiveRecord - module Generators - class SessionMigrationGenerator < Base - argument :name, :type => :string, :default => "add_sessions_table" - - def create_migration_file - migration_template "migration.rb", "db/migrate/#{file_name}.rb" - end - - protected - - def session_table_name - current_table_name = ActiveRecord::SessionStore::Session.table_name - if current_table_name == 'session' || current_table_name == 'sessions' - current_table_name = ActiveRecord::Base.pluralize_table_names ? 'sessions' : 'session' - end - current_table_name - end - - end - end -end diff --git a/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb b/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb deleted file mode 100644 index 9ea3248513..0000000000 --- a/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb +++ /dev/null @@ -1,12 +0,0 @@ -class <%= migration_class_name %> < ActiveRecord::Migration - def change - create_table :<%= session_table_name %> do |t| - t.string :session_id, :null => false - t.text :data - t.timestamps - end - - add_index :<%= session_table_name %>, :session_id - add_index :<%= session_table_name %>, :updated_at - end -end diff --git a/activerecord/test/cases/session_store/session_test.rb b/activerecord/test/cases/session_store/session_test.rb deleted file mode 100644 index a3b8ab74d9..0000000000 --- a/activerecord/test/cases/session_store/session_test.rb +++ /dev/null @@ -1,81 +0,0 @@ -require 'cases/helper' -require 'action_dispatch' -require 'active_record/session_store' - -module ActiveRecord - class SessionStore - class SessionTest < ActiveRecord::TestCase - self.use_transactional_fixtures = false - - attr_reader :session_klass - - def setup - super - ActiveRecord::Base.connection.schema_cache.clear! - Session.drop_table! if Session.table_exists? - @session_klass = Class.new(Session) - end - - def test_data_column_name - # default column name is 'data' - assert_equal 'data', Session.data_column_name - end - - def test_table_name - assert_equal 'sessions', Session.table_name - end - - def test_accessible_attributes - assert Session.accessible_attributes.include?(:session_id) - assert Session.accessible_attributes.include?(:data) - assert Session.accessible_attributes.include?(:marshaled_data) - end - - def test_create_table! - assert !Session.table_exists? - Session.create_table! - assert Session.table_exists? - Session.drop_table! - assert !Session.table_exists? - end - - def test_find_by_sess_id_compat - Session.reset_column_information - klass = Class.new(Session) do - def self.session_id_column - 'sessid' - end - end - klass.create_table! - - assert klass.columns_hash['sessid'], 'sessid column exists' - session = klass.new(:data => 'hello') - session.sessid = "100" - session.save! - - found = klass.find_by_session_id("100") - assert_equal session, found - assert_equal session.sessid, found.session_id - ensure - klass.drop_table! - Session.reset_column_information - end - - def test_find_by_session_id - Session.create_table! - session_id = "10" - s = session_klass.create!(:data => 'world', :session_id => session_id) - t = session_klass.find_by_session_id(session_id) - assert_equal s, t - assert_equal s.data, t.data - Session.drop_table! - end - - def test_loaded? - Session.create_table! - s = Session.new - assert !s.loaded?, 'session is not loaded' - end - end - end -end diff --git a/activerecord/test/cases/session_store/sql_bypass_test.rb b/activerecord/test/cases/session_store/sql_bypass_test.rb deleted file mode 100644 index b8cf4cf2cc..0000000000 --- a/activerecord/test/cases/session_store/sql_bypass_test.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'cases/helper' -require 'action_dispatch' -require 'active_record/session_store' - -module ActiveRecord - class SessionStore - class SqlBypassTest < ActiveRecord::TestCase - def setup - super - Session.drop_table! if Session.table_exists? - end - - def test_create_table - assert !Session.table_exists? - SqlBypass.create_table! - assert Session.table_exists? - SqlBypass.drop_table! - assert !Session.table_exists? - end - - def test_new_record? - s = SqlBypass.new :data => 'foo', :session_id => 10 - assert s.new_record?, 'this is a new record!' - end - - def test_persisted? - s = SqlBypass.new :data => 'foo', :session_id => 10 - assert !s.persisted?, 'this is a new record!' - end - - def test_not_loaded? - s = SqlBypass.new({}) - assert !s.loaded?, 'it is not loaded' - end - - def test_loaded? - s = SqlBypass.new :data => 'hello' - assert s.loaded?, 'it is loaded' - end - - def test_save - SqlBypass.create_table! unless Session.table_exists? - session_id = 20 - s = SqlBypass.new :data => 'hello', :session_id => session_id - s.save - t = SqlBypass.find_by_session_id session_id - assert_equal s.session_id, t.session_id - assert_equal s.data, t.data - end - - def test_destroy - SqlBypass.create_table! unless Session.table_exists? - session_id = 20 - s = SqlBypass.new :data => 'hello', :session_id => session_id - s.save - s.destroy - assert_nil SqlBypass.find_by_session_id session_id - end - - def test_data_column - SqlBypass.drop_table! if exists = Session.table_exists? - old, SqlBypass.data_column = SqlBypass.data_column, 'foo' - SqlBypass.create_table! - - session_id = 20 - SqlBypass.new(:data => 'hello', :session_id => session_id).save - assert_equal 'hello', SqlBypass.find_by_session_id(session_id).data - ensure - SqlBypass.drop_table! - SqlBypass.data_column = old - SqlBypass.create_table! if exists - end - end - end -end diff --git a/guides/code/getting_started/config/initializers/session_store.rb b/guides/code/getting_started/config/initializers/session_store.rb index 1a67af58b5..3b2ca93ab9 100644 --- a/guides/code/getting_started/config/initializers/session_store.rb +++ b/guides/code/getting_started/config/initializers/session_store.rb @@ -1,8 +1,3 @@ # Be sure to restart your server when you modify this file. Blog::Application.config.session_store :cookie_store, key: '_blog_session' - -# 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 generate session_migration") -# Blog::Application.config.session_store :active_record_store diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile index 109228f8c7..8748817eb8 100644 --- a/guides/source/active_support_core_extensions.textile +++ b/guides/source/active_support_core_extensions.textile @@ -1491,13 +1491,9 @@ For example, Action Pack uses this method to load the class that provides a cert # action_controller/metal/session_management.rb def session_store=(store) - if store == :active_record_store - self.session_store = ActiveRecord::SessionStore - else - @@session_store = store.is_a?(Symbol) ? - ActionDispatch::Session.const_get(store.to_s.camelize) : - store - end + @@session_store = store.is_a?(Symbol) ? + ActionDispatch::Session.const_get(store.to_s.camelize) : + store end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 7f05b2e7e1..f8ddeeb99e 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -125,8 +125,6 @@ module Rails case @session_store when :disabled nil - when :active_record_store - ActiveRecord::SessionStore when Symbol ActionDispatch::Session.const_get(@session_store.to_s.camelize) else diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 4fa990171d..a8c0626a41 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -173,7 +173,6 @@ module Rails "#{orm}:migration", "#{orm}:model", "#{orm}:observer", - "#{orm}:session_migration", "#{test}:controller", "#{test}:helper", "#{test}:integration", diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt index ff676280cb..4a099a4ce2 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt @@ -1,8 +1,3 @@ # Be sure to restart your server when you modify this file. <%= app_const %>.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %> - -# 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 generate session_migration"). -# <%= app_const %>.config.session_store :active_record_store diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index c2d4a0f2c8..d3bbac811c 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -163,26 +163,6 @@ module ApplicationTests end # AR - test "database middleware doesn't initialize when session store is not active_record" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.session_store :cookie_store, { :key => "blahblahblah" } - RUBY - require "#{app_path}/config/environment" - - assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore) - end - - test "database middleware initializes when session store is active record" do - add_to_config "config.session_store :active_record_store" - - require "#{app_path}/config/environment" - - expects = [ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore] - middleware = Rails.application.config.middleware.map { |m| m.klass } - assert_equal expects, middleware & expects - end - test "active_record extensions are applied to ActiveRecord" do add_to_config "config.active_record.table_name_prefix = 'tbl_'" require "#{app_path}/config/environment" diff --git a/railties/test/generators/session_migration_generator_test.rb b/railties/test/generators/session_migration_generator_test.rb deleted file mode 100644 index b590047ff0..0000000000 --- a/railties/test/generators/session_migration_generator_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/session_migration/session_migration_generator' - -class SessionMigrationGeneratorTest < Rails::Generators::TestCase - include GeneratorsTestHelper - - def test_session_migration_with_default_name - run_generator - assert_migration "db/migrate/add_sessions_table.rb", /class AddSessionsTable < ActiveRecord::Migration/ - end - - def test_session_migration_with_given_name - run_generator ["create_session_table"] - assert_migration "db/migrate/create_session_table.rb", /class CreateSessionTable < ActiveRecord::Migration/ - end - - def test_session_migration_with_custom_table_name - ActiveRecord::SessionStore::Session.table_name = "custom_table_name" - run_generator - assert_migration "db/migrate/add_sessions_table.rb" do |migration| - assert_match(/class AddSessionsTable < ActiveRecord::Migration/, migration) - assert_match(/create_table :custom_table_name/, migration) - end - ensure - ActiveRecord::SessionStore::Session.table_name = "sessions" - end -end