Permalink
Browse files

Merge pull request #39 from lcowell/development

added Domain middleware which switches databases based on the second level domain
  • Loading branch information...
bradrobertson committed Jun 1, 2012
2 parents e3d1688 + 2054bd2 commit 1e09ea2cf9b6f079fba1a1bf2ceaf35a3286d2ae
View
@@ -46,6 +46,7 @@ module Adapters
module Elevators
autoload :Subdomain, 'apartment/elevators/subdomain'
+ autoload :Domain, 'apartment/elevators/domain'
end
module Delayed
@@ -0,0 +1,32 @@
+module Apartment
+ module Elevators
+ # Provides a rack based db switching solution based on domain
+ # Assumes that database name should match domain
+ # Parses request host for second level domain
+ # eg. example.com => example
+ # www.example.bc.ca => example
+ class Domain
+
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ request = ActionDispatch::Request.new(env)
+
+ database = domain(request)
+
+ Apartment::Database.switch database if database
+
+ @app.call(env)
+ end
+
+ def domain(request)
+ return nil if request.host.blank?
+
+ request.host.match(/(www.)?(?<sld>[^.]*)/)["sld"]
+ end
+
+ end
+ end
+end
@@ -16,7 +16,8 @@ class Application < Rails::Application
# -- all .rb files in that directory are automatically loaded.
config.middleware.use 'Apartment::Elevators::Subdomain'
-
+ config.middleware.use 'Apartment::Elevators::Domain'
+
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Apartment::Elevators::Domain do
+
+ let(:company){ mock_model(Company, :domain => 'foo').as_null_object }
+ let(:domain){ "http://#{company.domain}.com" }
+ let(:api){ Apartment::Database }
+
+ before do
+ Apartment.seed_after_create = false
+ Apartment.use_postgres_schemas = true
+
+ api.create(company.domain)
+ end
+
+ after{ api.drop(company.domain) }
+
+ context "single request" do
+ it "should switch the db" do
+ ActiveRecord::Base.connection.schema_search_path.should_not == company.domain
+
+ visit(domain)
+ ActiveRecord::Base.connection.schema_search_path.should == company.domain
+ end
+ end
+
+ context "simultaneous requests" do
+ let(:company2){ mock_model(Company, :domain => 'bar').as_null_object }
+ let(:domain2){ "http://#{company2.domain}.com" }
+
+ before{ api.create(company2.domain) }
+ after{ api.drop(company2.domain) }
+
+ let!(:c1_user_count){ api.process(company.domain){ (2 + rand(2)).times{ User.create } } }
+ let!(:c2_user_count){ api.process(company2.domain){ (c1_user_count + 2).times{ User.create } } }
+
+ it "should fetch the correct user count for each session based on domain" do
+ visit(domain)
+
+ in_new_session do |session|
+ session.visit(domain2)
+ User.count.should == c2_user_count
+ end
+
+ visit(domain)
+ User.count.should == c1_user_count
+ end
+
+
+ end
+
+end
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Apartment::Elevators::Domain do
+
+ describe "#domain" do
+ it "parses the host for a domain name" do
+ request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
+ elevator = Apartment::Elevators::Domain.new(nil)
+ elevator.domain(request).should == 'example'
+ end
+
+ it "ignores a www prefix and domain suffix" do
+ request = ActionDispatch::Request.new('HTTP_HOST' => 'www.example.bc.ca')
+ elevator = Apartment::Elevators::Domain.new(nil)
+ elevator.domain(request).should == 'example'
+ end
+
+ it "returns nil if there is no host" do
+ request = ActionDispatch::Request.new('HTTP_HOST' => '')
+ elevator = Apartment::Elevators::Domain.new(nil)
+ elevator.domain(request).should be_nil
+ end
+
+ end
+
+end

0 comments on commit 1e09ea2

Please sign in to comment.