From 55bf0917cdb1d83776280f1d8863beea27d93ee9 Mon Sep 17 00:00:00 2001 From: Daniel Hoelbling Date: Mon, 7 May 2012 17:59:57 +0200 Subject: [PATCH] Added ability to have different serialize/deserialize methods for different scopes. Enables use-case where you store different Entities in different scopes (Like a Visitor and a AdminUser) --- lib/warden/manager.rb | 17 +++- lib/warden/session_serializer.rb | 10 +- spec/warden/scoped_session_serializer.rb | 123 +++++++++++++++++++++++ 3 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 spec/warden/scoped_session_serializer.rb diff --git a/lib/warden/manager.rb b/lib/warden/manager.rb index 5edceea..d5f7fae 100644 --- a/lib/warden/manager.rb +++ b/lib/warden/manager.rb @@ -58,24 +58,33 @@ class << self # Any object that can be serialized into the session in some way can be used as a "user" object # Generally however complex object should not be stored in the session. # If possible store only a "key" of the user object that will allow you to reconstitute it. + # + # You can supply different methods of serialization for different scopes by passing a scope symbol # # Example: # Warden::Manager.serialize_into_session{ |user| user.id } + # # With Scope: + # Warden::Manager.serialize_into_session(:admin) { |user| user.id } # # :api: public - def serialize_into_session(&block) - Warden::SessionSerializer.send :define_method, :serialize, &block + def serialize_into_session(scope = nil, &block) + method_name = scope.nil? ? :serialize : "#{scope}_serialize" + Warden::SessionSerializer.send :define_method, method_name, &block end # Reconstitues the user from the session. # Use the results of user_session_key to reconstitue the user from the session on requests after the initial login + # You can supply different methods of de-serialization for different scopes by passing a scope symbol # # Example: # Warden::Manager.serialize_from_session{ |id| User.get(id) } + # # With Scope: + # Warden::Manager.serialize_from_session(:admin) { |id| AdminUser.get(id) } # # :api: public - def serialize_from_session(&block) - Warden::SessionSerializer.send :define_method, :deserialize, &block + def serialize_from_session(scope = nil, &block) + method_name = scope.nil? ? :deserialize : "#{scope}_deserialize" + Warden::SessionSerializer.send :define_method, method_name, &block end end diff --git a/lib/warden/session_serializer.rb b/lib/warden/session_serializer.rb index 5d64237..5f9ee72 100644 --- a/lib/warden/session_serializer.rb +++ b/lib/warden/session_serializer.rb @@ -22,13 +22,17 @@ def deserialize(key) def store(user, scope) return unless user - session[key_for(scope)] = serialize(user) + method_name = "#{scope}_serialize" + specialized = respond_to?(method_name) + session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user) end def fetch(scope) key = session[key_for(scope)] return nil unless key - user = deserialize(key) + + method_name = "#{scope}_deserialize" + user = respond_to?(method_name) ? send(method_name, key) : deserialize(key) delete(scope) unless user user end @@ -41,4 +45,4 @@ def delete(scope, user=nil) session.delete(key_for(scope)) end end # SessionSerializer -end # Warden \ No newline at end of file +end # Warden diff --git a/spec/warden/scoped_session_serializer.rb b/spec/warden/scoped_session_serializer.rb new file mode 100644 index 0000000..98b28b0 --- /dev/null +++ b/spec/warden/scoped_session_serializer.rb @@ -0,0 +1,123 @@ +# encoding: utf-8 +require 'spec_helper' + +describe Warden::Manager do + before(:each) do + @env = env_with_params + @env['rack.session'] ||= {} + Warden::Manager.serialize_from_session { |k| k } + Warden::Manager.serialize_into_session { |u| u } + begin + Warden::SessionSerializer.send :remove_method, :admin_serialize + rescue + end + begin + Warden::SessionSerializer.send :remove_method, :admin_deserialize + rescue + end + end + after(:each) do + Warden::Manager.serialize_from_session { |k| k } + Warden::Manager.serialize_into_session { |u| u } + begin + Warden::SessionSerializer.send :remove_method, :admin_deserialize + Warden::SessionSerializer.send :remove_method, :admin_serialize + rescue + end + end + + def serializer_respond_to?(name) + Warden::SessionSerializer.new(@env).respond_to? name + end + + it "should respond to :serialize" do + serializer_respond_to?(:serialize).should == true + end + + it "should respond to :deserialize" do + serializer_respond_to?(:deserialize).should == true + end + + it "should respond to {scope}_deserialize if Manager.serialize_from_session is called with scope" do + Rack::Builder.new do + Warden::Manager.serialize_from_session ( :admin ) { |n| n } + end + serializer_respond_to?(:admin_deserialize).should == true + end + + it "should respond to {scope}_serialize if Manager.serialize_into_session is called with scope" do + Rack::Builder.new do + Warden::Manager.serialize_into_session(:admin) { |n| n } + end + serializer_respond_to?(:admin_serialize).should == true + end + + def initialize_with_scope(scope, &block) + Rack::Builder.new do + Warden::Manager.serialize_into_session(scope, &block) + end + end + + it "should execute serialize if no {scope}_serialize is present" do + serialized_object = nil + initialize_with_scope(nil) do |user| + serialized_object = user + user + end + serializer = Warden::SessionSerializer.new(@env) + serializer.store("user", :admin) + serialized_object.should == "user" + end + + it "should not have a {scope}_serialize by default" do + serializer_respond_to?(:admin_serialize).should == false + end + + it "should execute {scope}_serialize when calling store with a scope" do + serialized_object = nil + initialize_with_scope(:admin) do |user| + serialized_object = user + user + end + + serializer = Warden::SessionSerializer.new(@env) + serializer.store("user", :admin) + serialized_object.should == "user" + end + + + it "should execute {scope}_deserialize when calling store with a scope" do + serialized_object = nil + + Rack::Builder.new do + Warden::Manager.serialize_from_session(:admin) do |key| + serialized_object = key + key + end + end + + serializer = Warden::SessionSerializer.new(@env) + @env['rack.session'][serializer.key_for(:admin)] = "test" + serializer.fetch(:admin) + + serialized_object.should == "test" + end + + it "should execute deserialize if {scope}_deserialize is not present" do + serialized_object = nil + + Rack::Builder.new do + Warden::Manager.serialize_from_session do |key| + serialized_object = key + key + end + end + + serializer = Warden::SessionSerializer.new(@env) + @env['rack.session'][serializer.key_for(:admin)] = "test" + serializer.fetch(:admin) + + serialized_object.should == "test" + end + +end