forked from wycats/merb-plugins
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
233 additions
and
289 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
Merb::Generators::SessionMigrationGenerator.template :session_migration_activerecord, :orm => :activerecord do | ||
source(File.dirname(__FILE__), 'templates/session_migration/schema/migrations/%version%_sessions.rb') | ||
destination("schema/migrations/#{version}_sessions.rb") | ||
source(File.dirname(__FILE__), 'templates/session_migration/schema/migrations/%version%_database_sessions.rb') | ||
destination("schema/migrations/#{version}_database_sessions.rb") | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 50 additions & 127 deletions
177
merb_activerecord/lib/merb/session/active_record_session.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,142 +1,65 @@ | ||
require "active_record" | ||
require 'active_record' | ||
require 'merb-core/dispatch/session' | ||
require 'base64' | ||
|
||
module Merb | ||
module SessionMixin | ||
def setup_session | ||
before = cookies[_session_id_key] | ||
request.session, cookies[_session_id_key] = Merb::ActiveRecordSession.persist(cookies[_session_id_key]) | ||
@_fingerprint = Marshal.dump(request.session.data).hash | ||
@_new_cookie = cookies[_session_id_key] != before | ||
end | ||
|
||
def finalize_session | ||
request.session.save if @_fingerprint != Marshal.dump(request.session.data).hash | ||
set_cookie(_session_id_key, request.session.session_id, Time.now + _session_expiry) if (@_new_cookie || request.session.needs_new_cookie) | ||
end | ||
# Sessions stored in ActiveRecord model. | ||
# | ||
# To use ActiveRecord based sessions add the following to config/init.rb: | ||
# | ||
# Merb::Config[:session_store] = 'activerecord' | ||
|
||
class ActiveRecordSessionStore < ::ActiveRecord::Base | ||
|
||
table_name = (Merb::Plugins.config[:merb_active_record][:session_table_name] || "sessions") | ||
|
||
set_table_name table_name | ||
|
||
def session_store_type | ||
"activerecord" | ||
end | ||
end # ActiveRecordMixin | ||
|
||
class ActiveRecordSession < ::ActiveRecord::Base | ||
set_table_name 'sessions' | ||
# Customizable data column name. Defaults to 'data'. | ||
cattr_accessor :data_column_name | ||
self.data_column_name = 'data' | ||
before_save :marshal_data! | ||
before_save :raise_on_session_data_overflow! | ||
attr_accessor :needs_new_cookie | ||
|
||
serialize :data | ||
|
||
class << self | ||
# Generates a new session ID and creates a row for the new session in the database. | ||
def generate | ||
create(:session_id => Merb::SessionMixin::rand_uuid, :data => {}) | ||
end | ||
|
||
# Gets the existing session based on the <tt>session_id</tt> available in cookies. | ||
# If none is found, generates a new session. | ||
def persist(session_id) | ||
if session_id | ||
session = find_by_session_id(session_id) | ||
end | ||
unless session | ||
session = generate | ||
|
||
# ==== Parameters | ||
# session_id<String>:: ID of the session to retrieve. | ||
# | ||
# ==== Returns | ||
# ContainerSession:: The session corresponding to the ID. | ||
def retrieve_session(session_id) | ||
if item = find_by_session_id(session_id) | ||
item.data | ||
end | ||
[session, session.session_id] | ||
end | ||
|
||
# Don't try to reload ARStore::Session in dev mode. | ||
def reloadable? | ||
false | ||
end | ||
|
||
def data_column_size_limit | ||
@data_column_size_limit ||= columns_hash[@@data_column_name].limit | ||
end | ||
|
||
def marshal(data) Base64.encode64(Marshal.dump(data)) if data end | ||
def unmarshal(data) Marshal.load(Base64.decode64(data)) if data end | ||
|
||
def create_table! | ||
connection.execute <<-end_sql | ||
CREATE TABLE #{table_name} ( | ||
id INTEGER PRIMARY KEY, | ||
#{connection.quote_column_name('session_id')} TEXT UNIQUE, | ||
#{connection.quote_column_name(@@data_column_name)} TEXT(255) | ||
) | ||
end_sql | ||
# ==== Parameters | ||
# session_id<String>:: ID of the session to set. | ||
# data<ContainerSession>:: The session to set. | ||
def store_session(session_id, data) | ||
if item = find_by_session_id(session_id) | ||
item.update_attributes!(:data => data) | ||
else | ||
create(:session_id => session_id, :data => data) | ||
end | ||
end | ||
|
||
def drop_table! | ||
connection.execute "DROP TABLE #{table_name}" | ||
# ==== Parameters | ||
# session_id<String>:: ID of the session to delete. | ||
def delete_session(session_id) | ||
delete_all(["#{connection.quote_column_name('session_id')} IN (?)", session_id]) | ||
end | ||
end | ||
|
||
# Regenerate the Session ID | ||
def regenerate | ||
update_attributes(:session_id => Merb::SessionMixin::rand_uuid) | ||
self.needs_new_cookie = true | ||
end | ||
|
||
# Recreates the cookie with the default expiration time | ||
# Useful during log in for pushing back the expiration date | ||
def refresh_expiration | ||
self.needs_new_cookie = true | ||
end | ||
|
||
# Lazy-delete of session data | ||
def delete(key = nil) | ||
key ? self.data.delete(key) : self.data.clear | ||
end | ||
|
||
def [](key) | ||
data[key] | ||
end | ||
|
||
def empty? | ||
data.empty? | ||
end | ||
|
||
def each(&b) | ||
data.each(&b) | ||
|
||
end | ||
|
||
def each_with_index(&b) | ||
data.each_with_index(&b) | ||
end | ||
end | ||
|
||
def []=(key, val) | ||
data[key] = val | ||
end | ||
class ActiveRecordSession < SessionStoreContainer | ||
|
||
# Lazy-unmarshal session state. | ||
def data | ||
@data ||= self.class.unmarshal(read_attribute(@@data_column_name)) || {} | ||
end | ||
|
||
# Has the session been loaded yet? | ||
def loaded? | ||
!! @data | ||
end | ||
|
||
private | ||
attr_writer :data | ||
|
||
def marshal_data! | ||
return false if !loaded? | ||
write_attribute(@@data_column_name, self.class.marshal(self.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 if !loaded? | ||
limit = self.class.data_column_size_limit | ||
if loaded? and limit and read_attribute(@@data_column_name).size > limit | ||
raise MerbController::SessionOverflowError | ||
end | ||
end | ||
end # ActiveRecordSessionMixin | ||
end # Merb | ||
# The session store type | ||
self.session_store_type = :activerecord | ||
|
||
# The store object is the model class itself | ||
self.store = ActiveRecordSessionStore | ||
|
||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
merb_activerecord/specs/merb_active_record_session_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
$:.push File.join(File.dirname(__FILE__), '..', 'lib') | ||
require 'merb-core' | ||
require 'merb-core/test' | ||
require 'merb-core/test/helpers' | ||
|
||
Merb::BootLoader.before_app_loads do | ||
require "merb/session/active_record_session" | ||
end | ||
|
||
Merb.start_environment( :environment => 'test', :adapter => 'runner', | ||
:session_store => 'activerecord') | ||
|
||
Spec::Runner.configure do |config| | ||
config.include Merb::Test::RequestHelper | ||
end | ||
|
||
require 'merb_activerecord' | ||
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", | ||
:dbfile => ":memory:") | ||
|
||
ActiveRecord::Schema.define do | ||
create_table :sessions do |t| | ||
t.column :session_id, :string | ||
t.column :data, :text | ||
t.column :created_at, :datetime | ||
end | ||
end | ||
|
||
# Load up the shared specs from merb-core | ||
if (gem_spec = Gem.source_index.search('merb-core').last) && | ||
gem_spec.files.include?('spec/public/session/controllers/sessions.rb') | ||
require gem_spec.full_gem_path / 'spec/public/session/controllers/sessions.rb' | ||
require gem_spec.full_gem_path / 'spec/public/session/session_spec.rb' | ||
end | ||
|
||
describe Merb::ActiveRecordSession do | ||
|
||
before do | ||
@session_class = Merb::ActiveRecordSession | ||
@session = @session_class.generate | ||
end | ||
|
||
it_should_behave_like "All session-store backends" | ||
|
||
it "should have a session_store_type class attribute" do | ||
@session.class.session_store_type.should == :activerecord | ||
end | ||
|
||
end | ||
|
||
describe Merb::ActiveRecordSession, "mixed into Merb::Controller" do | ||
|
||
before(:all) { @session_class = Merb::ActiveRecordSession } | ||
|
||
it_should_behave_like "All session-stores mixed into Merb::Controller" | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
$TESTING = true | ||
$:.push File.join(File.dirname(__FILE__), '..', 'lib') | ||
require 'merb-core' | ||
require 'merb_activerecord' | ||
require 'merb/test/model_helper/active_record' | ||
require 'merb_activerecord' |
Oops, something went wrong.