From 06843f8794ad8c0368ece9ab57e340052f758025 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 22 Jul 2005 10:37:09 +0000 Subject: [PATCH] Added support for per-action session management #1763 git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1886 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 2 + actionpack/lib/action_controller.rb | 2 + .../lib/action_controller/cgi_process.rb | 4 +- .../action_controller/session_management.rb | 77 +++++++++++++++++++ .../lib/action_controller/test_process.rb | 2 +- .../controller/session_management_test.rb | 50 ++++++++++++ 6 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 actionpack/lib/action_controller/session_management.rb create mode 100644 actionpack/test/controller/session_management_test.rb diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index ac53fb277e..b88434e45d 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Added support for per-action session management #1763 + * Improved rendering speed on complicated templates by up to 25% #1234 [Stephan Kaes]. This did necessasitate a change to the internals of ActionView#render_template that now has four parameters. Developers of custom view handlers (like Amrita) need to update for that. * Added options hash as third argument to FormHelper#input, so you can do input('person', 'zip', :size=>10) #1719 [jeremye@bsa.ca.gov] diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index deead18b5a..253ff6a467 100755 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -50,6 +50,7 @@ require 'action_controller/components' require 'action_controller/verification' require 'action_controller/streaming' require 'action_controller/auto_complete' +require 'action_controller/session_management' require 'action_view' ActionController::Base.template_class = ActionView::Base @@ -71,4 +72,5 @@ ActionController::Base.class_eval do include ActionController::Verification include ActionController::Streaming include ActionController::AutoComplete + include ActionController::SessionManagement end diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index a8ac127ac7..1b36274dd9 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -37,7 +37,7 @@ module ActionController #:nodoc: end class CgiRequest < AbstractRequest #:nodoc: - attr_accessor :cgi + attr_accessor :cgi, :session_options DEFAULT_SESSION_OPTIONS = { :database_manager => CGI::Session::PStore, @@ -115,7 +115,7 @@ module ActionController #:nodoc: end def reset_session - @session.delete + @session.delete if CGI::Session === @session @session = (@session_options == false ? {} : new_session) end diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session_management.rb new file mode 100644 index 0000000000..8341575f64 --- /dev/null +++ b/actionpack/lib/action_controller/session_management.rb @@ -0,0 +1,77 @@ +module ActionController #:nodoc: + module SessionManagement #:nodoc: + def self.append_features(base) + super + base.extend(ClassMethods) + base.class_eval do + alias_method :process_without_session_management_support, :process + alias_method :process, :process_with_session_management_support + end + end + + module ClassMethods + # Specify how sessions ought to be managed for a subset of the actions on + # the controller. Like filters, you can specify :only and + # :except clauses to restrict the subset, otherwise options + # apply to all actions on this controller. + # + # The session options are inheritable, as well, so if you specify them in + # a parent controller, they apply to controllers that extend the parent. + # + # Usage: + # + # # turn off session management for all actions. + # session :off + # + # # turn off session management for all actions _except_ foo and bar. + # session :off, :except => %w(foo bar) + # + # # turn off session management for only the foo and bar actions. + # session :off, :only => %w(foo bar) + # + # # the session will only work over HTTPS, but only for the foo action + # session :only => :foo, :session_secure => true + # + # All session options described for ActionController::Base.process_cgi + # are valid arguments. + def session(*args) + options = Hash === args.last ? args.pop : {} + + options[:disabled] = true if !args.empty? + options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only] + options[:except] = [*options[:except]].map { |o| o.to_s } if options[:except] + if options[:only] && options[:except] + raise ArgumentError, "only one of either :only or :except are allowed" + end + + write_inheritable_array("session_options", [options]) + end + + def session_options_for(action) #:nodoc: + options = {} + + action = action.to_s + (read_inheritable_attribute("session_options") || []).each do |opts| + if opts[:only] && opts[:only].include?(action) + options.merge!(opts) + elsif opts[:except] && !opts[:except].include?(action) + options.merge!(opts) + elsif !opts[:only] && !opts[:except] + options.merge!(opts) + end + end + + options.delete :only + options.delete :except + + options[:disabled] ? false : options + end + end + + def process_with_session_management_support(request, response, method = :perform_action, *arguments) #:nodoc: + action = request.parameters["action"] || "index" + request.session_options = self.class.session_options_for(action) + process_without_session_management_support(request, response, method, *arguments) + end + end +end diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index 8e6c81b375..17953240c8 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -14,7 +14,7 @@ module ActionController #:nodoc: end class TestRequest < AbstractRequest #:nodoc: - attr_accessor :cookies + attr_accessor :cookies, :session_options attr_accessor :query_parameters, :request_parameters, :path, :session, :env attr_accessor :host diff --git a/actionpack/test/controller/session_management_test.rb b/actionpack/test/controller/session_management_test.rb new file mode 100644 index 0000000000..fef94f8263 --- /dev/null +++ b/actionpack/test/controller/session_management_test.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../abstract_unit' + +class SessionManagementTest < Test::Unit::TestCase + class SessionOffController < ActionController::Base + session :off + + def show + render_text "done" + end + + def tell + render_text "done" + end + end + + class TestController < ActionController::Base + session :off, :only => :show + session :session_secure => true, :except => :show + + def show + render_text "done" + end + + def tell + render_text "done" + end + end + + def setup + @request, @response = ActionController::TestRequest.new, + ActionController::TestResponse.new + end + + def test_session_off_globally + @controller = SessionOffController.new + get :show + assert_equal false, @request.session_options + get :tell + assert_equal false, @request.session_options + end + + def test_session_off_conditionally + @controller = TestController.new + get :show + assert_equal false, @request.session_options + get :tell + assert_instance_of Hash, @request.session_options + assert @request.session_options[:session_secure] + end +end