apartment 0.23.0 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +8 -2
  4. data/Guardfile +24 -0
  5. data/HISTORY.md +5 -0
  6. data/README.md +20 -0
  7. data/apartment.gemspec +3 -3
  8. data/lib/apartment.rb +14 -11
  9. data/lib/apartment/adapters/abstract_adapter.rb +3 -3
  10. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +4 -4
  11. data/lib/apartment/adapters/mysql2_adapter.rb +3 -2
  12. data/lib/apartment/adapters/postgresql_adapter.rb +12 -3
  13. data/lib/apartment/adapters/sqlite3_adapter.rb +2 -2
  14. data/lib/apartment/elevators/domain.rb +3 -3
  15. data/lib/apartment/elevators/first_subdomain.rb +2 -2
  16. data/lib/apartment/elevators/generic.rb +7 -2
  17. data/lib/apartment/elevators/host_hash.rb +1 -1
  18. data/lib/apartment/elevators/subdomain.rb +9 -9
  19. data/lib/apartment/migrator.rb +9 -4
  20. data/lib/apartment/version.rb +1 -1
  21. data/lib/generators/apartment/install/templates/apartment.rb +8 -0
  22. data/lib/tasks/apartment.rake +6 -6
  23. data/spec/dummy/config/application.rb +0 -3
  24. data/spec/examples/schema_adapter_examples.rb +13 -0
  25. data/spec/unit/{middleware/domain_elevator_spec.rb → elevators/domain_spec.rb} +14 -7
  26. data/spec/unit/{middleware/first_subdomain_elevator_spec.rb → elevators/first_subdomain_spec.rb} +1 -1
  27. data/spec/unit/elevators/generic_spec.rb +37 -0
  28. data/spec/unit/elevators/host_hash_spec.rb +32 -0
  29. data/spec/unit/elevators/subdomain_spec.rb +36 -0
  30. data/spec/unit/migrator_spec.rb +23 -76
  31. data/spec/unit/reloader_spec.rb +1 -1
  32. metadata +20 -28
  33. data/circle.yml +0 -9
  34. data/spec/examples/elevator_examples.rb +0 -31
  35. data/spec/integration/middleware/domain_elevator_spec.rb +0 -10
  36. data/spec/integration/middleware/generic_elevator_spec.rb +0 -11
  37. data/spec/integration/middleware/subdomain_elevator_spec.rb +0 -35
  38. data/spec/unit/middleware/host_hash_elevator_spec.rb +0 -25
  39. data/spec/unit/middleware/subdomain_elevator_spec.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7048e41db332f308d96362525ecd55389c7b6ad2
4
- data.tar.gz: c303cac42eca0c9d5a22263fb8d2b3abb239b07e
3
+ metadata.gz: 7a231a3932b1b2bd5718861c0f70201d7502d4dd
4
+ data.tar.gz: 45ebf27d557562aaf6944b471fb5ea679f4b0d84
5
5
  SHA512:
6
- metadata.gz: ab730aab830bf546295ecd75dabc017dd1fe01a55bbf82b625ff0f9e70cd7a58034417afe25344c7c36ff9f9e1f75eec7a73a4d07432fc1f6acc4e03291548ab
7
- data.tar.gz: 0d7041eaea15f04e43ab772adfbbebb51f35451215a619882162d337d9bb25bbffbf3c9bbfb0e73ece50935681a45adc8d1ecb55e9d1ceeae38823a2dbd73134
6
+ metadata.gz: d2b3e6efe7075333081133c60f96150ccb0227422545f669de98a8bf5db82bd971fa48a474448b3152238282c1201ec502bad5f16419fdbd4da985fa4aa30081
7
+ data.tar.gz: b6d1f23c13731c723c566af5f9e77ef4116d75b031b689f8333ee2773cf56c36806b8a7d023e2302372d9eba01c3e04bd23383edd662e0ae18e9b7958cd875f1
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *.gem
2
2
  .bundle
3
3
  *.lock
4
+ gemfiles/*.lock
4
5
  pkg/*
5
6
  *.log
6
7
  .idea
data/.travis.yml CHANGED
@@ -2,8 +2,14 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
- - jruby-19mode-1.7.4
5
+ - 2.1.0
6
+ - jruby-19mode
6
7
  gemfile:
7
8
  - gemfiles/rails3.2.gemfile
8
9
  - gemfiles/rails4.0.gemfile
9
- bundler_args: --without local --verbose
10
+ bundler_args: --without local --verbose
11
+ before_install:
12
+ - gem install bundler -v '> 1.5.0'
13
+ env:
14
+ RUBY_GC_MALLOC_LIMIT: 90000000
15
+ RUBY_FREE_MIN: 200000
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/apartment/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
7
+ watch(%r{^lib/apartment/(.+)\.rb$}) { |m| "spec/integration/#{m[1]}_spec.rb" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
+
10
+ # # Rails example
11
+ # watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ # watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
13
+ # watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
14
+ # watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
15
+ # watch('config/routes.rb') { "spec/routing" }
16
+ # watch('app/controllers/application_controller.rb') { "spec/controllers" }
17
+
18
+ # # Capybara features specs
19
+ # watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
20
+
21
+ # # Turnip features and steps
22
+ # watch(%r{^spec/acceptance/(.+)\.feature$})
23
+ # watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
24
+ end
data/HISTORY.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.23.1
2
+ * January 8, 2014
3
+
4
+ - Schema adapters now initialize with default and persistent schemas
5
+
1
6
  # 0.23.0
2
7
  * August 21, 2013
3
8
 
data/README.md CHANGED
@@ -19,6 +19,15 @@ Add the following to your Gemfile:
19
19
  gem 'apartment'
20
20
  ```
21
21
 
22
+ Then generate your `Apartment` config file using
23
+
24
+ ```ruby
25
+ bundle exec rails generate apartment:install
26
+ ```
27
+
28
+ This will create a `config/initializers/apartment.rb` initializer file.
29
+ Configure as needed using the docs below.
30
+
22
31
  That's all you need to set up the Apartment libraries. If you want to switch databases
23
32
  on a per-user basis, look under "Usage - Switching databases per request", below.
24
33
 
@@ -70,6 +79,17 @@ database, call switch with no arguments.
70
79
  You can have Apartment route to the appropriate database by adding some Rack middleware.
71
80
  Apartment can support many different "Elevators" that can take care of this routing to your data.
72
81
 
82
+ The initializer above will generate the appropriate code for the Subdomain elevator
83
+ by default. You can see this in `config/initializers/apartment.rb` after running
84
+ that generator. If you're *not* using the generator, you can specify your
85
+ elevator below. Note that in this case you will **need** to require the elevator
86
+ manually in your `application.rb` like so
87
+
88
+ ```ruby
89
+ # config/application.rb
90
+ require 'apartment/elevators/subdomain' # or 'domain' or 'generic'
91
+ ```
92
+
73
93
  **Switch on subdomain**
74
94
  In house, we use the subdomain elevator, which analyzes the subdomain of the request and switches to a database schema of the same name. It can be used like so:
75
95
 
data/apartment.gemspec CHANGED
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
23
23
 
24
24
  s.add_development_dependency 'appraisal'
25
25
  s.add_development_dependency 'rake', '~> 0.9'
26
- s.add_development_dependency 'rspec', '~> 2.11'
27
- s.add_development_dependency 'rspec-rails', '~> 2.11'
26
+ s.add_development_dependency 'rspec-rails', '~> 2.14'
27
+ s.add_development_dependency 'guard-rspec', '~> 4.2'
28
28
  s.add_development_dependency 'capybara', '~> 1.0.0'
29
29
 
30
30
  if defined?(JRUBY_VERSION)
@@ -39,4 +39,4 @@ Gem::Specification.new do |s|
39
39
  s.add_development_dependency 'pg', '>= 0.11.0'
40
40
  s.add_development_dependency 'sqlite3'
41
41
  end
42
- end
42
+ end
data/lib/apartment.rb CHANGED
@@ -68,23 +68,26 @@ module Apartment
68
68
  end
69
69
 
70
70
  # Exceptions
71
- class ApartmentError < StandardError; end
71
+ ApartmentError = Class.new(StandardError)
72
72
 
73
73
  # Raised when apartment cannot find the adapter specified in <tt>config/database.yml</tt>
74
- class AdapterNotFound < ApartmentError; end
74
+ AdapterNotFound = Class.new(ApartmentError)
75
75
 
76
- # Raised when database cannot find the specified database
77
- class DatabaseNotFound < ApartmentError; end
76
+ # Tenant specified is unknown
77
+ TenantNotFound = Class.new(ApartmentError)
78
78
 
79
- # Raised when trying to create a database that already exists
80
- class DatabaseExists < ApartmentError; end
79
+ # Raised when database cannot find the specified database
80
+ DatabaseNotFound = Class.new(TenantNotFound)
81
81
 
82
82
  # Raised when database cannot find the specified schema
83
- class SchemaNotFound < ApartmentError; end
83
+ SchemaNotFound = Class.new(TenantNotFound)
84
84
 
85
- # Raised when trying to create a schema that already exists
86
- class SchemaExists < ApartmentError; end
85
+ # The Tenant attempting to be created already exists
86
+ TenantExists = Class.new(ApartmentError)
87
87
 
88
- # Raised when an ActiveRecord object does not have the required database field on it
89
- class DJSerializationError < ApartmentError; end
88
+ # Raised when trying to create a database that already exists
89
+ DatabaseExists = Class.new(TenantExists)
90
+
91
+ # Raised when trying to create a schema that already exists
92
+ SchemaExists = Class.new(TenantExists)
90
93
  end
@@ -14,7 +14,7 @@ module Apartment
14
14
  # @param {String} database Database name
15
15
  #
16
16
  def create(database)
17
- create_database(database)
17
+ create_tenant(database)
18
18
 
19
19
  process(database) do
20
20
  import_database_schema
@@ -106,7 +106,7 @@ module Apartment
106
106
  #
107
107
  # @param {String} database Database name
108
108
  #
109
- def create_database(database)
109
+ def create_tenant(database)
110
110
  Apartment.connection.create_database( environmentify(database) )
111
111
 
112
112
  rescue *rescuable_exceptions
@@ -183,4 +183,4 @@ module Apartment
183
183
  end
184
184
  end
185
185
  end
186
- end
186
+ end
@@ -5,8 +5,8 @@ module Apartment
5
5
 
6
6
  def self.jdbc_postgresql_adapter(config)
7
7
  Apartment.use_schemas ?
8
- Adapters::JDBCPostgresqlSchemaAdapter.new(config) :
9
- Adapters::JDBCPostgresqlAdapter.new(config)
8
+ Adapters::JDBCPostgresqlSchemaAdapter.new(config) :
9
+ Adapters::JDBCPostgresqlAdapter.new(config)
10
10
  end
11
11
  end
12
12
 
@@ -17,7 +17,7 @@ module Apartment
17
17
 
18
18
  protected
19
19
 
20
- def create_database(database)
20
+ def create_tenant(database)
21
21
  # There is a bug in activerecord-jdbcpostgresql-adapter (1.2.5) that will cause
22
22
  # an exception if no options are passed into the create_database call.
23
23
  Apartment.connection.create_database(environmentify(database), { :thisisahack => '' })
@@ -64,4 +64,4 @@ module Apartment
64
64
  end
65
65
  end
66
66
  end
67
- end
67
+ end
@@ -33,9 +33,10 @@ module Apartment
33
33
  attr_reader :default_database
34
34
 
35
35
  def initialize(config)
36
- @default_database = config[:database]
37
-
38
36
  super
37
+
38
+ @default_database = config[:database]
39
+ reset
39
40
  end
40
41
 
41
42
  # Reset current_database to the default_database
@@ -24,6 +24,12 @@ module Apartment
24
24
  # Separate Adapter for Postgresql when using schemas
25
25
  class PostgresqlSchemaAdapter < AbstractAdapter
26
26
 
27
+ def initialize(config)
28
+ super
29
+
30
+ reset
31
+ end
32
+
27
33
  # Drop the database schema
28
34
  #
29
35
  # @param {String} database Database (schema) to drop
@@ -83,7 +89,7 @@ module Apartment
83
89
 
84
90
  # Create the new schema
85
91
  #
86
- def create_database(database)
92
+ def create_tenant(database)
87
93
  Apartment.connection.execute(%{CREATE SCHEMA "#{database}"})
88
94
 
89
95
  rescue *rescuable_exceptions
@@ -95,8 +101,11 @@ module Apartment
95
101
  # Generate the final search path to set including persistent_schemas
96
102
  #
97
103
  def full_search_path
98
- persistent_schemas = Apartment.persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
99
- %{"#{@current_database.to_s}"} + (persistent_schemas.empty? ? "" : ", #{persistent_schemas}")
104
+ persistent_schemas.map(&:inspect).join(", ")
105
+ end
106
+
107
+ def persistent_schemas
108
+ [@current_database, Apartment.persistent_schemas].flatten
100
109
  end
101
110
  end
102
111
  end
@@ -26,7 +26,7 @@ module Apartment
26
26
  File.basename(Apartment.connection.instance_variable_get(:@config)[:database], '.sqlite3')
27
27
  end
28
28
 
29
- protected
29
+ protected
30
30
 
31
31
  def connect_to_new(database)
32
32
  raise DatabaseNotFound,
@@ -35,7 +35,7 @@ module Apartment
35
35
  super database_file(database)
36
36
  end
37
37
 
38
- def create_database(database)
38
+ def create_tenant(database)
39
39
  raise DatabaseExists,
40
40
  "The database #{environmentify(database)} already exists." if File.exists?(database_file(database))
41
41
 
@@ -2,15 +2,15 @@ require 'apartment/elevators/generic'
2
2
 
3
3
  module Apartment
4
4
  module Elevators
5
- # Provides a rack based db switching solution based on domain
6
- # Assumes that database name should match domain
5
+ # Provides a rack based tenant switching solution based on domain
6
+ # Assumes that tenant name should match domain
7
7
  # Parses request host for second level domain
8
8
  # eg. example.com => example
9
9
  # www.example.bc.ca => example
10
10
  #
11
11
  class Domain < Generic
12
12
 
13
- def parse_database_name(request)
13
+ def parse_tenant_name(request)
14
14
  return nil if request.host.blank?
15
15
 
16
16
  request.host.match(/(www\.)?(?<sld>[^.]*)/)["sld"]
@@ -2,14 +2,14 @@ require 'apartment/elevators/subdomain'
2
2
 
3
3
  module Apartment
4
4
  module Elevators
5
- # Provides a rack based db switching solution based on the first subdomain
5
+ # Provides a rack based tenant switching solution based on the first subdomain
6
6
  # of a given domain name.
7
7
  # eg:
8
8
  # - example1.domain.com => example1
9
9
  # - example2.something.domain.com => example2
10
10
  class FirstSubdomain < Subdomain
11
11
 
12
- def parse_database_name(request)
12
+ def parse_tenant_name(request)
13
13
  super.split('.')[0]
14
14
  end
15
15
  end
@@ -3,13 +3,13 @@ require 'apartment/database'
3
3
 
4
4
  module Apartment
5
5
  module Elevators
6
- # Provides a rack based db switching solution based on request
6
+ # Provides a rack based tenant switching solution based on request
7
7
  #
8
8
  class Generic
9
9
 
10
10
  def initialize(app, processor = nil)
11
11
  @app = app
12
- @processor = processor || method(:parse_database_name)
12
+ @processor = processor || method(:parse_tenant_name)
13
13
  end
14
14
 
15
15
  def call(env)
@@ -23,6 +23,11 @@ module Apartment
23
23
  end
24
24
 
25
25
  def parse_database_name(request)
26
+ warn "[DEPRECATED] - Use #parse_tenant_name"
27
+ parse_tenant_name(request)
28
+ end
29
+
30
+ def parse_tenant_name(request)
26
31
  raise "Override"
27
32
  end
28
33
  end
@@ -11,7 +11,7 @@ module Apartment
11
11
  @hash = hash
12
12
  end
13
13
 
14
- def parse_database_name(request)
14
+ def parse_tenant_name(request)
15
15
  raise DatabaseNotFound,
16
16
  "Cannot find database for host #{request.host}" unless @hash.has_key?(request.host)
17
17
 
@@ -2,33 +2,33 @@ require 'apartment/elevators/generic'
2
2
 
3
3
  module Apartment
4
4
  module Elevators
5
- # Provides a rack based db switching solution based on subdomains
6
- # Assumes that database name should match subdomain
5
+ # Provides a rack based tenant switching solution based on subdomains
6
+ # Assumes that tenant name should match subdomain
7
7
  #
8
8
  class Subdomain < Generic
9
9
  def self.excluded_subdomains
10
- @@excluded_subdomains ||= []
10
+ @excluded_subdomains ||= []
11
11
  end
12
12
 
13
13
  def self.excluded_subdomains=(arg)
14
- @@excluded_subdomains = arg
14
+ @excluded_subdomains = arg
15
15
  end
16
16
 
17
- def parse_database_name(request)
17
+ def parse_tenant_name(request)
18
18
  request_subdomain = subdomain(request.host)
19
19
 
20
- # If the domain acquired is set to be exlcluded, set the database to whatever is currently
20
+ # If the domain acquired is set to be excluded, set the tenant to whatever is currently
21
21
  # next in line in the schema search path.
22
- database = if self.class.excluded_subdomains.include?(request_subdomain)
22
+ tenant = if self.class.excluded_subdomains.include?(request_subdomain)
23
23
  nil
24
24
  else
25
25
  request_subdomain
26
26
  end
27
27
 
28
- database.present? && database || nil
28
+ tenant.presence
29
29
  end
30
30
 
31
- private
31
+ protected
32
32
 
33
33
  # *Almost* a direct ripoff of ActionDispatch::Request subdomain methods
34
34
 
@@ -8,7 +8,9 @@ module Apartment
8
8
  # Migrate to latest
9
9
  def migrate(database)
10
10
  Database.process(database) do
11
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_path, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
11
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
12
+
13
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_path, version) do |migration|
12
14
  ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
13
15
  end
14
16
  end
@@ -16,13 +18,16 @@ module Apartment
16
18
 
17
19
  # Migrate up/down to a specific version
18
20
  def run(direction, database, version)
19
- Database.process(database){ ActiveRecord::Migrator.run(direction, ActiveRecord::Migrator.migrations_path, version) }
21
+ Database.process(database) do
22
+ ActiveRecord::Migrator.run(direction, ActiveRecord::Migrator.migrations_path, version)
23
+ end
20
24
  end
21
25
 
22
26
  # rollback latest migration `step` number of times
23
27
  def rollback(database, step = 1)
24
- Database.process(database){ ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_path, step) }
28
+ Database.process(database) do
29
+ ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_path, step)
30
+ end
25
31
  end
26
32
  end
27
-
28
33
  end
@@ -1,3 +1,3 @@
1
1
  module Apartment
2
- VERSION = "0.23.0"
2
+ VERSION = "0.23.1"
3
3
  end
@@ -1,3 +1,9 @@
1
+ # Require whichever elevator you're using below here...
2
+ #
3
+ # require 'apartment/elevators/generic'
4
+ # require 'apartment/elevators/domain'
5
+ require 'apartment/elevators/subdomain'
6
+
1
7
  #
2
8
  # Apartment Configuration
3
9
  #
@@ -5,6 +11,8 @@ Apartment.configure do |config|
5
11
 
6
12
  # these models will not be multi-tenanted,
7
13
  # but remain in the global (public) namespace
14
+ # Note that ActiveRecord::SessionStore::Session is just an example
15
+ # you may not even use the AR Session Store, in which case you'd remove that line
8
16
  config.excluded_models = %w{
9
17
  ActiveRecord::SessionStore::Session
10
18
  }
@@ -8,7 +8,7 @@ apartment_namespace = namespace :apartment do
8
8
  begin
9
9
  puts("Creating #{db} database")
10
10
  quietly { Apartment::Database.create(db) }
11
- rescue Apartment::DatabaseExists, Apartment::SchemaExists => e
11
+ rescue Apartment::TenantExists => e
12
12
  puts e.message
13
13
  end
14
14
  end
@@ -21,7 +21,7 @@ apartment_namespace = namespace :apartment do
21
21
  begin
22
22
  puts("Migrating #{db} database")
23
23
  Apartment::Migrator.migrate db
24
- rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
24
+ rescue Apartment::TenantNotFound => e
25
25
  puts e.message
26
26
  end
27
27
  end
@@ -36,7 +36,7 @@ apartment_namespace = namespace :apartment do
36
36
  Apartment::Database.process(db) do
37
37
  Apartment::Database.seed
38
38
  end
39
- rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
39
+ rescue Apartment::TenantNotFound => e
40
40
  puts e.message
41
41
  end
42
42
  end
@@ -50,7 +50,7 @@ apartment_namespace = namespace :apartment do
50
50
  begin
51
51
  puts("Rolling back #{db} database")
52
52
  Apartment::Migrator.rollback db, step
53
- rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
53
+ rescue Apartment::TenantNotFound => e
54
54
  puts e.message
55
55
  end
56
56
  end
@@ -67,7 +67,7 @@ apartment_namespace = namespace :apartment do
67
67
  begin
68
68
  puts("Migrating #{db} database up")
69
69
  Apartment::Migrator.run :up, db, version
70
- rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
70
+ rescue Apartment::TenantNotFound => e
71
71
  puts e.message
72
72
  end
73
73
  end
@@ -82,7 +82,7 @@ apartment_namespace = namespace :apartment do
82
82
  begin
83
83
  puts("Migrating #{db} database down")
84
84
  Apartment::Migrator.run :down, db, version
85
- rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
85
+ rescue Apartment::TenantNotFound => e
86
86
  puts e.message
87
87
  end
88
88
  end
@@ -18,9 +18,6 @@ module Dummy
18
18
  require 'apartment/elevators/domain'
19
19
 
20
20
  config.middleware.use 'Apartment::Elevators::Subdomain'
21
- config.middleware.use 'Apartment::Elevators::Domain'
22
- # Our test for this middleware is using a query_string couldn't think of a better way to differentiate it from the other middleware
23
- config.middleware.use 'Apartment::Elevators::Generic', Proc.new { |request| request.query_string.split('=').last if request.query_string.present? }
24
21
 
25
22
  # Custom directories with classes and modules you want to be autoloadable.
26
23
  config.autoload_paths += %W(#{config.root}/lib)
@@ -28,6 +28,19 @@ shared_examples_for "a schema based apartment adapter" do
28
28
 
29
29
  Company.table_name.should == "#{default_schema}.companies"
30
30
  end
31
+
32
+ it 'sets the search_path correctly' do
33
+ Apartment::Database.init
34
+
35
+ User.connection.schema_search_path.should =~ %r|#{default_schema}|
36
+ end
37
+ end
38
+
39
+ context "persistent_schemas", :persistent_schemas => true do
40
+ it "sets the persistent schemas in the schema_search_path" do
41
+ Apartment::Database.init
42
+ connection.schema_search_path.should end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
43
+ end
31
44
  end
32
45
  end
33
46
 
@@ -3,23 +3,30 @@ require 'apartment/elevators/domain'
3
3
 
4
4
  describe Apartment::Elevators::Domain do
5
5
 
6
- describe "#parse_database_name" do
6
+ subject(:elevator){ described_class.new(Proc.new{}) }
7
+
8
+ describe "#parse_tenant_name" do
7
9
  it "parses the host for a domain name" do
8
10
  request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
9
- elevator = Apartment::Elevators::Domain.new(nil)
10
- elevator.parse_database_name(request).should == 'example'
11
+ elevator.parse_tenant_name(request).should == 'example'
11
12
  end
12
13
 
13
14
  it "ignores a www prefix and domain suffix" do
14
15
  request = ActionDispatch::Request.new('HTTP_HOST' => 'www.example.bc.ca')
15
- elevator = Apartment::Elevators::Domain.new(nil)
16
- elevator.parse_database_name(request).should == 'example'
16
+ elevator.parse_tenant_name(request).should == 'example'
17
17
  end
18
18
 
19
19
  it "returns nil if there is no host" do
20
20
  request = ActionDispatch::Request.new('HTTP_HOST' => '')
21
- elevator = Apartment::Elevators::Domain.new(nil)
22
- elevator.parse_database_name(request).should be_nil
21
+ elevator.parse_tenant_name(request).should be_nil
22
+ end
23
+ end
24
+
25
+ describe "#call" do
26
+ it "switches to the proper tenant" do
27
+ Apartment::Database.should_receive(:switch).with('example')
28
+
29
+ elevator.call('HTTP_HOST' => 'www.example.com')
23
30
  end
24
31
  end
25
32
  end
@@ -3,7 +3,7 @@ require 'apartment/elevators/first_subdomain'
3
3
 
4
4
  describe Apartment::Elevators::FirstSubdomain do
5
5
  describe "subdomain" do
6
- subject { described_class.new("test").parse_database_name(request) }
6
+ subject { described_class.new("test").parse_tenant_name(request) }
7
7
  let(:request) { double(:request, :host => "#{subdomain}.example.com") }
8
8
 
9
9
  context "one subdomain" do
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'apartment/elevators/generic'
3
+
4
+ describe Apartment::Elevators::Generic do
5
+
6
+ class MyElevator < described_class
7
+ def parse_tenant_name(*)
8
+ 'tenant2'
9
+ end
10
+ end
11
+
12
+ subject(:elevator){ described_class.new(Proc.new{}) }
13
+
14
+ describe "#call" do
15
+ it "calls the processor if given" do
16
+ elevator = described_class.new(Proc.new{}, Proc.new{'tenant1'})
17
+
18
+ Apartment::Database.should_receive(:switch).with('tenant1')
19
+
20
+ elevator.call('HTTP_HOST' => 'foo.bar.com')
21
+ end
22
+
23
+ it "raises if parse_tenant_name not implemented" do
24
+ expect {
25
+ elevator.call('HTTP_HOST' => 'foo.bar.com')
26
+ }.to raise_error(RuntimeError)
27
+ end
28
+
29
+ it "switches to the parsed db_name" do
30
+ elevator = MyElevator.new(Proc.new{})
31
+
32
+ Apartment::Database.should_receive(:switch).with('tenant2')
33
+
34
+ elevator.call('HTTP_HOST' => 'foo.bar.com')
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'apartment/elevators/host_hash'
3
+
4
+ describe Apartment::Elevators::HostHash do
5
+
6
+ subject(:elevator){ Apartment::Elevators::HostHash.new(Proc.new{}, 'example.com' => 'example_tenant') }
7
+
8
+ describe "#parse_tenant_name" do
9
+ it "parses the host for a domain name" do
10
+ request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
11
+ elevator.parse_tenant_name(request).should == 'example_tenant'
12
+ end
13
+
14
+ it "raises DatabaseNotFound exception if there is no host" do
15
+ request = ActionDispatch::Request.new('HTTP_HOST' => '')
16
+ expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::DatabaseNotFound)
17
+ end
18
+
19
+ it "raises DatabaseNotFound exception if there is no database associated to current host" do
20
+ request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
21
+ expect { elevator.parse_tenant_name(request) }.to raise_error(Apartment::DatabaseNotFound)
22
+ end
23
+ end
24
+
25
+ describe "#call" do
26
+ it "switches to the proper tenant" do
27
+ Apartment::Database.should_receive(:switch).with('example_tenant')
28
+
29
+ elevator.call('HTTP_HOST' => 'example.com')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'apartment/elevators/subdomain'
3
+
4
+ describe Apartment::Elevators::Subdomain do
5
+
6
+ subject(:elevator){ described_class.new(Proc.new{}) }
7
+
8
+ describe "#parse_tenant_name" do
9
+ it "should parse subdomain" do
10
+ request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
11
+ elevator.parse_tenant_name(request).should == 'foo'
12
+ end
13
+
14
+ it "should return nil when no subdomain" do
15
+ request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com')
16
+ elevator.parse_tenant_name(request).should be_nil
17
+ end
18
+ end
19
+
20
+ describe "#call" do
21
+ it "switches to the proper tenant" do
22
+ Apartment::Database.should_receive(:switch).with('tenant1')
23
+ elevator.call('HTTP_HOST' => 'tenant1.example.com')
24
+ end
25
+
26
+ it "ignores excluded subdomains" do
27
+ described_class.excluded_subdomains = %w{foo}
28
+
29
+ Apartment::Database.should_not_receive(:switch)
30
+
31
+ elevator.call('HTTP_HOST' => 'foo.bar.com')
32
+
33
+ described_class.excluded_subdomains = nil
34
+ end
35
+ end
36
+ end
@@ -1,90 +1,37 @@
1
1
  require 'spec_helper'
2
2
  require 'apartment/migrator'
3
3
 
4
- describe Apartment::Migrator, database: :postgresql do
4
+ describe Apartment::Migrator do
5
5
 
6
- let(:schema_name){ Apartment::Test.next_db }
7
- let(:version){ 20110613152810 } # note this is brittle! I've literally just taken the version of the one migration I made... don't change this version
6
+ let(:tenant){ Apartment::Test.next_db }
8
7
 
9
- before do
10
- ActiveRecord::Base.establish_connection config
11
- Apartment::Database.stub(:config).and_return config # Use postgresql config for this test
12
- @original_schema = ActiveRecord::Base.connection.schema_search_path
13
- # Necessary because the JDBC adapter returns $user in the search path
14
- @original_schema.gsub!(/"\$user",/, '') if defined?(JRUBY_VERSION)
8
+ # Don't need a real switch here, just testing behaviour
9
+ before { Apartment::Database.adapter.stub(:connect_to_new) }
15
10
 
16
- Apartment.configure do |config|
17
- config.use_schemas = true
18
- config.excluded_models = []
19
- config.database_names = [schema_name]
20
- end
21
-
22
- Apartment::Database.create schema_name # create the schema
23
- migrations_path = Rails.root + ActiveRecord::Migrator.migrations_path # tell AR where the real migrations are
24
- ActiveRecord::Migrator.stub(:migrations_path).and_return(migrations_path)
25
- end
11
+ describe "::migrate" do
12
+ it "processes and migrates" do
13
+ expect(Apartment::Database).to receive(:process).with(tenant).and_call_original
14
+ expect(ActiveRecord::Migrator).to receive(:migrate)
26
15
 
27
- after do
28
- Apartment::Test.drop_schema(schema_name)
16
+ Apartment::Migrator.migrate(tenant)
17
+ end
29
18
  end
30
19
 
31
- # reset db
32
- after(:all){ Apartment::Test.load_schema }
33
-
34
- context "postgresql" do
35
- context "using schemas" do
36
-
37
- describe "#migrate" do
38
- it "should connect to new db, then reset when done" do
39
- ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
40
- ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
41
- Apartment::Migrator.migrate(schema_name)
42
- end
43
-
44
- it "should migrate db" do
45
- ActiveRecord::Migrator.should_receive(:migrate)
46
- Apartment::Migrator.migrate(schema_name)
47
- end
48
- end
20
+ describe "::run" do
21
+ it "processes and runs" do
22
+ expect(Apartment::Database).to receive(:process).with(tenant).and_call_original
23
+ expect(ActiveRecord::Migrator).to receive(:run).with(:up, anything, 1234)
49
24
 
50
- describe "#run" do
51
- context "up" do
52
-
53
- it "should connect to new db, then reset when done" do
54
- ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
55
- ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
56
- Apartment::Migrator.run(:up, schema_name, version)
57
- end
58
-
59
- it "should migrate to a version" do
60
- ActiveRecord::Migrator.should_receive(:run).with(:up, anything, version)
61
- Apartment::Migrator.run(:up, schema_name, version)
62
- end
63
- end
64
-
65
- describe "down" do
66
-
67
- it "should connect to new db, then reset when done" do
68
- ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
69
- ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
70
- Apartment::Migrator.run(:down, schema_name, version)
71
- end
72
-
73
- it "should migrate to a version" do
74
- ActiveRecord::Migrator.should_receive(:run).with(:down, anything, version)
75
- Apartment::Migrator.run(:down, schema_name, version)
76
- end
77
- end
78
- end
25
+ Apartment::Migrator.run(:up, tenant, 1234)
26
+ end
27
+ end
79
28
 
80
- describe "#rollback" do
81
- let(:steps){ 3 }
29
+ describe "::rollback" do
30
+ it "processes and rolls back" do
31
+ expect(Apartment::Database).to receive(:process).with(tenant).and_call_original
32
+ expect(ActiveRecord::Migrator).to receive(:rollback).with(anything, 2)
82
33
 
83
- it "should rollback the db" do
84
- ActiveRecord::Migrator.should_receive(:rollback).with(anything, steps)
85
- Apartment::Migrator.rollback(schema_name, steps)
86
- end
87
- end
34
+ Apartment::Migrator.rollback(tenant, 2)
88
35
  end
89
36
  end
90
- end
37
+ end
@@ -13,7 +13,7 @@ describe Apartment::Reloader do
13
13
  Company.reset_table_name # ensure we're clean
14
14
  end
15
15
 
16
- subject{ Apartment::Reloader.new(mock("Rack::Application", :call => nil)) }
16
+ subject{ Apartment::Reloader.new(double("Rack::Application", :call => nil)) }
17
17
 
18
18
  it "should initialize apartment when called" do
19
19
  Company.table_name.should_not include('public.')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apartment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0
4
+ version: 0.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Brunner
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-15 00:00:00.000000000 Z
12
+ date: 2014-01-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -68,33 +68,33 @@ dependencies:
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0.9'
70
70
  - !ruby/object:Gem::Dependency
71
- name: rspec
71
+ name: rspec-rails
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ~>
75
75
  - !ruby/object:Gem::Version
76
- version: '2.11'
76
+ version: '2.14'
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - ~>
82
82
  - !ruby/object:Gem::Version
83
- version: '2.11'
83
+ version: '2.14'
84
84
  - !ruby/object:Gem::Dependency
85
- name: rspec-rails
85
+ name: guard-rspec
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - ~>
89
89
  - !ruby/object:Gem::Version
90
- version: '2.11'
90
+ version: '4.2'
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - ~>
96
96
  - !ruby/object:Gem::Version
97
- version: '2.11'
97
+ version: '4.2'
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: capybara
100
100
  requirement: !ruby/object:Gem::Requirement
@@ -168,16 +168,14 @@ files:
168
168
  - .travis.yml
169
169
  - Appraisals
170
170
  - Gemfile
171
+ - Guardfile
171
172
  - HISTORY.md
172
173
  - README.md
173
174
  - Rakefile
174
175
  - TODO.md
175
176
  - apartment.gemspec
176
- - circle.yml
177
177
  - gemfiles/rails3.2.gemfile
178
- - gemfiles/rails3.2.gemfile.lock
179
178
  - gemfiles/rails4.0.gemfile
180
- - gemfiles/rails4.0.gemfile.lock
181
179
  - lib/apartment.rb
182
180
  - lib/apartment/adapters/abstract_adapter.rb
183
181
  - lib/apartment/adapters/abstract_jdbc_adapter.rb
@@ -245,13 +243,9 @@ files:
245
243
  - spec/dummy/public/stylesheets/.gitkeep
246
244
  - spec/dummy/script/rails
247
245
  - spec/examples/connection_adapter_examples.rb
248
- - spec/examples/elevator_examples.rb
249
246
  - spec/examples/generic_adapter_examples.rb
250
247
  - spec/examples/schema_adapter_examples.rb
251
248
  - spec/integration/apartment_rake_integration_spec.rb
252
- - spec/integration/middleware/domain_elevator_spec.rb
253
- - spec/integration/middleware/generic_elevator_spec.rb
254
- - spec/integration/middleware/subdomain_elevator_spec.rb
255
249
  - spec/integration/query_caching_spec.rb
256
250
  - spec/schemas/v1.rb
257
251
  - spec/schemas/v2.rb
@@ -265,10 +259,11 @@ files:
265
259
  - spec/support/setup.rb
266
260
  - spec/tasks/apartment_rake_spec.rb
267
261
  - spec/unit/config_spec.rb
268
- - spec/unit/middleware/domain_elevator_spec.rb
269
- - spec/unit/middleware/first_subdomain_elevator_spec.rb
270
- - spec/unit/middleware/host_hash_elevator_spec.rb
271
- - spec/unit/middleware/subdomain_elevator_spec.rb
262
+ - spec/unit/elevators/domain_spec.rb
263
+ - spec/unit/elevators/first_subdomain_spec.rb
264
+ - spec/unit/elevators/generic_spec.rb
265
+ - spec/unit/elevators/host_hash_spec.rb
266
+ - spec/unit/elevators/subdomain_spec.rb
272
267
  - spec/unit/migrator_spec.rb
273
268
  - spec/unit/reloader_spec.rb
274
269
  homepage: https://github.com/influitive/apartment
@@ -291,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
286
  version: '0'
292
287
  requirements: []
293
288
  rubyforge_project:
294
- rubygems_version: 2.1.10
289
+ rubygems_version: 2.1.11
295
290
  signing_key:
296
291
  specification_version: 4
297
292
  summary: A Ruby gem for managing database multitenancy
@@ -339,13 +334,9 @@ test_files:
339
334
  - spec/dummy/public/stylesheets/.gitkeep
340
335
  - spec/dummy/script/rails
341
336
  - spec/examples/connection_adapter_examples.rb
342
- - spec/examples/elevator_examples.rb
343
337
  - spec/examples/generic_adapter_examples.rb
344
338
  - spec/examples/schema_adapter_examples.rb
345
339
  - spec/integration/apartment_rake_integration_spec.rb
346
- - spec/integration/middleware/domain_elevator_spec.rb
347
- - spec/integration/middleware/generic_elevator_spec.rb
348
- - spec/integration/middleware/subdomain_elevator_spec.rb
349
340
  - spec/integration/query_caching_spec.rb
350
341
  - spec/schemas/v1.rb
351
342
  - spec/schemas/v2.rb
@@ -359,9 +350,10 @@ test_files:
359
350
  - spec/support/setup.rb
360
351
  - spec/tasks/apartment_rake_spec.rb
361
352
  - spec/unit/config_spec.rb
362
- - spec/unit/middleware/domain_elevator_spec.rb
363
- - spec/unit/middleware/first_subdomain_elevator_spec.rb
364
- - spec/unit/middleware/host_hash_elevator_spec.rb
365
- - spec/unit/middleware/subdomain_elevator_spec.rb
353
+ - spec/unit/elevators/domain_spec.rb
354
+ - spec/unit/elevators/first_subdomain_spec.rb
355
+ - spec/unit/elevators/generic_spec.rb
356
+ - spec/unit/elevators/host_hash_spec.rb
357
+ - spec/unit/elevators/subdomain_spec.rb
366
358
  - spec/unit/migrator_spec.rb
367
359
  - spec/unit/reloader_spec.rb
data/circle.yml DELETED
@@ -1,9 +0,0 @@
1
- machine:
2
- ruby:
3
- version: 1.9.3-p194
4
-
5
- test:
6
- override:
7
- - bundle exec rake spec:
8
- environment:
9
- RAILS_ENV: test
@@ -1,31 +0,0 @@
1
- require 'spec_helper'
2
-
3
- shared_examples_for "an apartment elevator" do
4
-
5
- context "single request" do
6
- it "should switch the db" do
7
- ActiveRecord::Base.connection.schema_search_path.should_not == %{"#{db1}"}
8
-
9
- visit(domain1)
10
- ActiveRecord::Base.connection.schema_search_path.should == %{"#{db1}"}
11
- end
12
- end
13
-
14
- context "simultaneous requests" do
15
-
16
- let!(:c1_user_count) { api.process(db1){ (2 + rand(2)).times{ User.create } } }
17
- let!(:c2_user_count) { api.process(db2){ (c1_user_count + 2).times{ User.create } } }
18
-
19
- it "should fetch the correct user count for each session based on the elevator processor" do
20
- visit(domain1)
21
-
22
- in_new_session do |session|
23
- session.visit(domain2)
24
- User.count.should == c2_user_count
25
- end
26
-
27
- visit(domain1)
28
- User.count.should == c1_user_count
29
- end
30
- end
31
- end
@@ -1,10 +0,0 @@
1
- require 'spec_helper'
2
- require 'apartment/elevators/domain'
3
-
4
- describe Apartment::Elevators::Domain, elevator: true do
5
-
6
- let(:domain1) { "http://#{db1}.com" }
7
- let(:domain2) { "http://#{db2}.com" }
8
-
9
- it_should_behave_like "an apartment elevator"
10
- end
@@ -1,11 +0,0 @@
1
- require 'spec_helper'
2
- require 'apartment/elevators/generic'
3
-
4
- describe Apartment::Elevators::Generic, elevator: true do
5
-
6
- # NOTE, see spec/dummy/config/application.rb to see the Proc that defines the behaviour here
7
- let(:domain1) { "http://#{db1}.com?db=#{db1}" }
8
- let(:domain2) { "http://#{db2}.com?db=#{db2}" }
9
-
10
- it_should_behave_like "an apartment elevator"
11
- end
@@ -1,35 +0,0 @@
1
- require 'spec_helper'
2
- require 'apartment/elevators/generic'
3
-
4
- describe Apartment::Elevators::Subdomain, elevator: true do
5
-
6
- let(:domain1) { "http://#{db1}.example.com" }
7
- let(:domain2) { "http://#{db2}.example.com" }
8
-
9
- it_should_behave_like "an apartment elevator"
10
-
11
- context "With Subdomain Excluded" do
12
- let(:domain_with_excluded_subdomain) { "http://www.example.com" }
13
-
14
- before do
15
- Apartment::Elevators::Subdomain.excluded_subdomains = %w(www)
16
- # FIXME:
17
- # This is used because the dummy app includes all three middlewares. The domain middleware specifically
18
- # tries to lookup the example schema and tries to switch to it. I don't know how to go around this.
19
- Apartment::Database.create("example")
20
- end
21
-
22
- it_should_behave_like "an apartment elevator"
23
-
24
- it "shouldnt switch the schema if the subdomain is excluded" do
25
- ActiveRecord::Base.connection.schema_search_path.scan(/\w+/).should_not include("www")
26
- visit(domain_with_excluded_subdomain)
27
- ActiveRecord::Base.connection.schema_search_path.scan(/\w+/).should_not include("www")
28
- end
29
-
30
- after do
31
- Apartment::Elevators::Subdomain.excluded_subdomains = []
32
- Apartment::Database.drop("example")
33
- end
34
- end
35
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
- require 'apartment/elevators/host_hash'
3
-
4
- describe Apartment::Elevators::HostHash do
5
-
6
- describe "#parse_database_name" do
7
- it "parses the host for a domain name" do
8
- request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
9
- elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
10
- elevator.parse_database_name(request).should == 'example_database'
11
- end
12
-
13
- it "raises DatabaseNotFound exception if there is no host" do
14
- request = ActionDispatch::Request.new('HTTP_HOST' => '')
15
- elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
16
- expect { elevator.parse_database_name(request) }.to raise_error(Apartment::DatabaseNotFound)
17
- end
18
-
19
- it "raises DatabaseNotFound exception if there is no database associated to current host" do
20
- request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
21
- elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
22
- expect { elevator.parse_database_name(request) }.to raise_error(Apartment::DatabaseNotFound)
23
- end
24
- end
25
- end
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
- require 'apartment/elevators/subdomain'
3
-
4
- describe Apartment::Elevators::Subdomain do
5
-
6
- describe "#parse_database_name" do
7
- it "should parse subdomain" do
8
- request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
9
- elevator = Apartment::Elevators::Subdomain.new(nil)
10
- elevator.parse_database_name(request).should == 'foo'
11
- end
12
-
13
- it "should return nil when no subdomain" do
14
- request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com')
15
- elevator = Apartment::Elevators::Subdomain.new(nil)
16
- elevator.parse_database_name(request).should be_nil
17
- end
18
- end
19
- end