micro_sessions 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +72 -0
- data/init.rb +3 -0
- data/lib/micro_sessions/controller.rb +30 -0
- data/lib/micro_sessions/helpers.rb +27 -0
- data/lib/micro_sessions/micro_session.rb +40 -0
- data/lib/micro_sessions/railtie.rb +19 -0
- data/lib/micro_sessions/version.rb +3 -0
- data/lib/micro_sessions.rb +25 -0
- data/spec/controller_spec.rb +80 -0
- data/spec/helpers_spec.rb +24 -0
- data/spec/spec_helper.rb +10 -0
- metadata +111 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Ben Hughes
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
== Micro Sessions
|
2
|
+
|
3
|
+
In terms of passing data amongst HTTP requests there are really two options:
|
4
|
+
* Param or form data passing
|
5
|
+
* Storing in cookies
|
6
|
+
* Storing in server-side session, keyed off an ID stored as a cookie.
|
7
|
+
|
8
|
+
For a certain application where you're using number 3, this comes at a cost - the session is "global". In other words, in a single browser window with multiple tabs, the server side cannot distinguish between individual "sessions" *within* that browser session. This gem introduces a third, more granular method:
|
9
|
+
* Storing in server-side session, keyed off an ID stored as a cookie *and* keyed off a request parameter.
|
10
|
+
|
11
|
+
This could be useful in instances such as a very complex wizard where transmitting the entire history of data RESTfully via param passing may not be feasible, yet you'd still like to support multiple tabs within the same browser window separately.
|
12
|
+
|
13
|
+
== In-Progress
|
14
|
+
|
15
|
+
This gem is not useable and is being continually worked on. Will be released as 0.1.0 once reasonably working and stable.
|
16
|
+
|
17
|
+
DO NOT USE!
|
18
|
+
|
19
|
+
== Installation
|
20
|
+
|
21
|
+
This gem requires ActionPack and ActiveSupport 3.0 or greater.
|
22
|
+
|
23
|
+
Include the gem in your Gemfile:
|
24
|
+
|
25
|
+
gem "micro_sessions"
|
26
|
+
|
27
|
+
== Usage
|
28
|
+
|
29
|
+
Simply include the middleware in your controller:
|
30
|
+
|
31
|
+
class ApplicationController
|
32
|
+
micro_sessions
|
33
|
+
end
|
34
|
+
|
35
|
+
By default the name of the request parameter used to differentiate micro-sessions is "_msid", though this can be configured:
|
36
|
+
|
37
|
+
class ApplicationController
|
38
|
+
micro_sessions :key => "_msid"
|
39
|
+
end
|
40
|
+
|
41
|
+
By default the key generated will be a 10-digit random hash, though this can be configured as well:
|
42
|
+
|
43
|
+
class ApplicationController
|
44
|
+
micro_sessions :type => :integer, :length => 10
|
45
|
+
end
|
46
|
+
|
47
|
+
Valid values for +:type+: are:
|
48
|
+
* +:random_hash+
|
49
|
+
* +:integer+ (simply increments from one)
|
50
|
+
* +:random_integer+ (random integer with a maximum of +:length+ digits)
|
51
|
+
|
52
|
+
Session data is accessible to the controller and view through the +micro_session+ object, which works identically to the +session+ object but it specific to the micro-session:
|
53
|
+
|
54
|
+
micro_session[:key] = "Value"
|
55
|
+
micro_session[:key] # => "Value"
|
56
|
+
|
57
|
+
When transitioning between pages for which you'd like to keep the micro-session alive, the request parameter must be passed along with any link, form, or redirect. The preferred way is to make use of the new +:micro_session+ option on available on the +url_for+ helper, which will accept either a specific value or just "true" to use the "current" micro-session to this request:
|
58
|
+
|
59
|
+
link_to user_path(@user, :micro_session => true)
|
60
|
+
redirect_to user_project_path([@user, @project], :micro_session => true)
|
61
|
+
|
62
|
+
If you wish to transmit the identifier via a form, be sure to include the hidden field:
|
63
|
+
|
64
|
+
<% form_for(@user) do |f| %>
|
65
|
+
<%= micro_session_hidden_field %>
|
66
|
+
...
|
67
|
+
<% end %>
|
68
|
+
|
69
|
+
Destroying a micro-session is as easy as:
|
70
|
+
|
71
|
+
micro_session.destroy
|
72
|
+
|
data/init.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module MicroSessions
|
2
|
+
module Controller
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def micro_sessions(options = {})
|
7
|
+
options.stringify_keys!
|
8
|
+
options.assert_valid_keys(:param, :param_type, :key, :length, :counter)
|
9
|
+
|
10
|
+
options[:param] ||= "_msid"
|
11
|
+
options[:key] ||= "_micro_sessions"
|
12
|
+
options[:param_type] ||= :hash
|
13
|
+
options[:length] ||= 10
|
14
|
+
options[:counter] ||= 1
|
15
|
+
|
16
|
+
class_inheritable_accessor :micro_session_options
|
17
|
+
self.micro_session_options = options
|
18
|
+
|
19
|
+
class_eval do
|
20
|
+
def micro_session
|
21
|
+
@micro_session ||= MicroSessions::MicroSession.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
helper_method :micro_session
|
25
|
+
helper_method :micro_session_options
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MicroSessions
|
2
|
+
module Helpers
|
3
|
+
module UrlHelper
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module InstanceMethods
|
7
|
+
def url_for(options = {})
|
8
|
+
if options.is_a?(Hash) && ms_value = options.delete(:micro_sessions) && !micro_session.empty?
|
9
|
+
options[micro_session.options[:param]] = (ms_value == true ? micro_session.id : ms_value)
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module FormTagHelper
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
def micro_session_hidden_field
|
22
|
+
hidden_field_tag controller.class.micro_session_options[:param], micro_session.id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module MicroSessions
|
2
|
+
class MicroSession
|
3
|
+
def initialize(controller)
|
4
|
+
@controller = controller
|
5
|
+
end
|
6
|
+
|
7
|
+
def options
|
8
|
+
@controller.class.micro_session_options
|
9
|
+
end
|
10
|
+
|
11
|
+
def data
|
12
|
+
@controller.session[options[:key]] ||= {}
|
13
|
+
@controller.session[options[:key]][id] ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
delegate :empty?, :[], :[]=, :to_h, :to_hash, :to => :data
|
17
|
+
|
18
|
+
def id
|
19
|
+
@id ||= id_from_params || generate_id
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def id_from_params
|
26
|
+
@controller.params[options[:param]] if @controller.params
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_id
|
30
|
+
case options[:param_type]
|
31
|
+
when :hash
|
32
|
+
ActiveSupport::SecureRandom.hex(options[:length] / 2)
|
33
|
+
when :integer
|
34
|
+
self.counter += 1
|
35
|
+
when :random_integer
|
36
|
+
ActiveSupport::SecureRandom.integer
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MicroSessions
|
2
|
+
if defined?(Rails::Railtie)
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
initializer "micro_sessions.insert" do
|
5
|
+
ActiveSupport.on_load(:action_controller) do
|
6
|
+
MicroSessions::Railtie.insert
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Railtie
|
13
|
+
def self.insert
|
14
|
+
ActionController::Base.send(:include, MicroSessions::Controller)
|
15
|
+
ActionView::Helpers::UrlHelper.send(:include, MicroSessions::Helpers::UrlHelper)
|
16
|
+
ActionView::Helpers::FormTagHelper.send(:include, MicroSessions::Helpers::FormTagHelper)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
unless defined?(ActionController)
|
2
|
+
begin
|
3
|
+
require "action_pack"
|
4
|
+
require "action_controller"
|
5
|
+
require "action_view"
|
6
|
+
rescue LoadError
|
7
|
+
require "rubygems"
|
8
|
+
require_gem "actionpack"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module MicroSessions
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
extend ActiveSupport::Autoload
|
15
|
+
|
16
|
+
autoload :Controller
|
17
|
+
autoload :Helpers
|
18
|
+
autoload :MicroSession
|
19
|
+
|
20
|
+
included do
|
21
|
+
include MicroSessions::Controller
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require "micro_sessions/railtie"
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MicroSessions::Controller do
|
4
|
+
context "with a controller" do
|
5
|
+
before do
|
6
|
+
@controller_class = class SampleController < ActionController::Base
|
7
|
+
micro_sessions
|
8
|
+
self
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should default param to _msid" do
|
13
|
+
@controller_class.micro_session_options[:param].should == "_msid"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should default key to _micro_sessions" do
|
17
|
+
@controller_class.micro_session_options[:key].should == "_micro_sessions"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should default length to 10" do
|
21
|
+
@controller_class.micro_session_options[:length].should == 10
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should default counter to 1" do
|
25
|
+
@controller_class.micro_session_options[:counter].should == 1
|
26
|
+
end
|
27
|
+
|
28
|
+
context "an instance of the controller" do
|
29
|
+
before do
|
30
|
+
@controller = @controller_class.new
|
31
|
+
@controller.stub(:params).and_return({})
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should expose #micro_session as a method" do
|
35
|
+
@controller.micro_session.should be_an_instance_of(MicroSessions::MicroSession)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should generate a 10-character hash id" do
|
39
|
+
@controller.micro_session.id.should be_a(String)
|
40
|
+
@controller.micro_session.id.size.should == 10
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with micro session data and another controller" do
|
44
|
+
before do
|
45
|
+
@micro_session_data = {
|
46
|
+
:integer => 1,
|
47
|
+
:string => "String"
|
48
|
+
}
|
49
|
+
|
50
|
+
@another_controller = @controller_class.new
|
51
|
+
@another_controller.stub(:params).and_return({})
|
52
|
+
@another_controller.stub(:session).and_return({
|
53
|
+
"_micro_sessions" => {@controller.micro_session.id => @micro_session_data}
|
54
|
+
})
|
55
|
+
end
|
56
|
+
|
57
|
+
context "without passing id" do
|
58
|
+
subject do
|
59
|
+
@another_controller.micro_session
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not have data" do
|
63
|
+
subject.data.should == {}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when passing id" do
|
68
|
+
subject do
|
69
|
+
@another_controller.stub(:params).and_return({"_msid" => @controller.micro_session.id})
|
70
|
+
@another_controller.micro_session
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should have data" do
|
74
|
+
subject.data.should == @micro_session_data
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MicroSessions::Helpers do
|
4
|
+
before do
|
5
|
+
@controller_class = Class.new(ActionController::Base)
|
6
|
+
@controller_class.stub(:micro_session_options).and_return(:param => "_msid")
|
7
|
+
@helpers = ActionView::Base.new
|
8
|
+
@helpers.stub(:controller).and_return(@controller_class.new)
|
9
|
+
@helpers.stub(:micro_session).and_return(mock(:id => "abc123"))
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should respond to #micro_session_hidden_field" do
|
13
|
+
@helpers.should respond_to(:micro_session_hidden_field)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should render correct micro_session_hidden_field" do
|
17
|
+
@helpers.micro_session_hidden_field.should == %{<input id="_msid" name="_msid" type="hidden" value="abc123" />}
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO: This is way too complex to test, requires an enormous amount of stubbing... Need a real Rails app.
|
21
|
+
# it "should render correct link_to with :micro_sessions => true" do
|
22
|
+
# @helpers.url_for
|
23
|
+
# end
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: micro_sessions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ben Hughes
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-23 00:00:00 +03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: actionpack
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 3.0.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: activesupport
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 7
|
46
|
+
segments:
|
47
|
+
- 3
|
48
|
+
- 0
|
49
|
+
- 0
|
50
|
+
version: 3.0.0
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Provides 'micro-sessions' within the global sessions object keyed off an identifier.
|
54
|
+
email: ben@railsgarden.com
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- lib/micro_sessions/controller.rb
|
63
|
+
- lib/micro_sessions/helpers.rb
|
64
|
+
- lib/micro_sessions/micro_session.rb
|
65
|
+
- lib/micro_sessions/railtie.rb
|
66
|
+
- lib/micro_sessions/version.rb
|
67
|
+
- lib/micro_sessions.rb
|
68
|
+
- spec/controller_spec.rb
|
69
|
+
- spec/helpers_spec.rb
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
- LICENSE
|
72
|
+
- README.rdoc
|
73
|
+
- init.rb
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/rubiety/micro_sessions
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 19
|
98
|
+
segments:
|
99
|
+
- 1
|
100
|
+
- 3
|
101
|
+
- 4
|
102
|
+
version: 1.3.4
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: micro_sessions
|
106
|
+
rubygems_version: 1.3.7
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Keyed sessions within the global sessions object.
|
110
|
+
test_files: []
|
111
|
+
|