apartment 0.22.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.rspec +2 -1
  4. data/.travis.yml +3 -1
  5. data/Appraisals +7 -0
  6. data/Gemfile +0 -21
  7. data/HISTORY.md +6 -0
  8. data/README.md +13 -71
  9. data/Rakefile +4 -2
  10. data/TODO.md +0 -5
  11. data/apartment.gemspec +19 -0
  12. data/gemfiles/rails3.2.gemfile +7 -0
  13. data/gemfiles/rails4.0.gemfile +7 -0
  14. data/lib/apartment.rb +2 -28
  15. data/lib/apartment/adapters/abstract_adapter.rb +0 -2
  16. data/lib/apartment/adapters/abstract_jdbc_adapter.rb +2 -0
  17. data/lib/apartment/adapters/jdbc_mysql_adapter.rb +2 -0
  18. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +1 -1
  19. data/lib/apartment/adapters/mysql2_adapter.rb +2 -3
  20. data/lib/apartment/adapters/postgis_adapter.rb +0 -1
  21. data/lib/apartment/adapters/postgresql_adapter.rb +2 -3
  22. data/lib/apartment/adapters/sqlite3_adapter.rb +2 -0
  23. data/lib/apartment/database.rb +0 -4
  24. data/lib/apartment/elevators/domain.rb +2 -0
  25. data/lib/apartment/elevators/first_subdomain.rb +2 -0
  26. data/lib/apartment/elevators/generic.rb +3 -0
  27. data/lib/apartment/elevators/host_hash.rb +2 -0
  28. data/lib/apartment/elevators/subdomain.rb +19 -2
  29. data/lib/apartment/migrator.rb +2 -1
  30. data/lib/apartment/railtie.rb +2 -2
  31. data/lib/apartment/reloader.rb +0 -3
  32. data/lib/apartment/version.rb +2 -2
  33. data/lib/tasks/apartment.rake +2 -0
  34. data/spec/adapters/jdbc_mysql_adapter_spec.rb +1 -3
  35. data/spec/adapters/jdbc_postgresql_adapter_spec.rb +1 -3
  36. data/spec/adapters/mysql2_adapter_spec.rb +1 -2
  37. data/spec/adapters/postgresql_adapter_spec.rb +1 -2
  38. data/spec/adapters/sqlite3_adapter_spec.rb +1 -2
  39. data/spec/database_spec.rb +32 -50
  40. data/spec/dummy/app/models/user.rb +0 -2
  41. data/spec/dummy/config/application.rb +2 -0
  42. data/spec/dummy/config/environments/development.rb +2 -0
  43. data/spec/dummy/config/environments/production.rb +2 -0
  44. data/spec/dummy/config/environments/test.rb +1 -2
  45. data/spec/dummy/config/initializers/apartment.rb +1 -1
  46. data/spec/dummy/db/seeds.rb +1 -4
  47. data/spec/examples/elevator_examples.rb +4 -4
  48. data/spec/integration/apartment_rake_integration_spec.rb +15 -19
  49. data/spec/integration/middleware/domain_elevator_spec.rb +4 -3
  50. data/spec/integration/middleware/generic_elevator_spec.rb +4 -3
  51. data/spec/integration/middleware/subdomain_elevator_spec.rb +29 -3
  52. data/spec/integration/query_caching_spec.rb +8 -4
  53. data/spec/schemas/v1.rb +16 -0
  54. data/spec/schemas/v2.rb +43 -0
  55. data/spec/schemas/v3.rb +49 -0
  56. data/spec/spec_helper.rb +5 -11
  57. data/spec/support/apartment_helpers.rb +4 -2
  58. data/spec/support/contexts.rb +15 -19
  59. data/spec/support/requirements.rb +1 -17
  60. data/spec/support/setup.rb +47 -0
  61. data/spec/tasks/apartment_rake_spec.rb +6 -3
  62. data/spec/unit/config_spec.rb +3 -3
  63. data/spec/unit/middleware/domain_elevator_spec.rb +1 -2
  64. data/spec/{integration → unit}/middleware/first_subdomain_elevator_spec.rb +1 -0
  65. data/spec/unit/middleware/host_hash_elevator_spec.rb +1 -2
  66. data/spec/unit/middleware/subdomain_elevator_spec.rb +1 -2
  67. data/spec/unit/migrator_spec.rb +5 -4
  68. data/spec/unit/reloader_spec.rb +6 -4
  69. metadata +130 -14
  70. data/lib/apartment/delayed_job/enqueue.rb +0 -26
  71. data/lib/apartment/delayed_job/hooks.rb +0 -26
  72. data/lib/apartment/delayed_job/psych_ext.rb +0 -61
  73. data/lib/apartment/delayed_job/requirements.rb +0 -23
  74. data/lib/apartment/delayed_job/syck_ext.rb +0 -29
  75. data/spec/dummy/lib/fake_dj_class.rb +0 -6
  76. data/spec/integration/delayed_job_integration_spec.rb +0 -99
@@ -1,3 +1,5 @@
1
+ require 'apartment/elevators/generic'
2
+
1
3
  module Apartment
2
4
  module Elevators
3
5
  # Provides a rack based db switching solution based on domain
@@ -1,3 +1,5 @@
1
+ require 'apartment/elevators/subdomain'
2
+
1
3
  module Apartment
2
4
  module Elevators
3
5
  # Provides a rack based db switching solution based on the first subdomain
@@ -1,3 +1,6 @@
1
+ require 'rack/request'
2
+ require 'apartment/database'
3
+
1
4
  module Apartment
2
5
  module Elevators
3
6
  # Provides a rack based db switching solution based on request
@@ -1,3 +1,5 @@
1
+ require 'apartment/elevators/generic'
2
+
1
3
  module Apartment
2
4
  module Elevators
3
5
  # Provides a rack based db switching solution based on hosts
@@ -1,12 +1,29 @@
1
+ require 'apartment/elevators/generic'
2
+
1
3
  module Apartment
2
4
  module Elevators
3
5
  # Provides a rack based db switching solution based on subdomains
4
6
  # Assumes that database name should match subdomain
5
7
  #
6
8
  class Subdomain < Generic
9
+ def self.excluded_subdomains
10
+ @@excluded_subdomains ||= []
11
+ end
12
+
13
+ def self.excluded_subdomains=(arg)
14
+ @@excluded_subdomains = arg
15
+ end
7
16
 
8
17
  def parse_database_name(request)
9
- database = subdomain(request.host)
18
+ request_subdomain = subdomain(request.host)
19
+
20
+ # If the domain acquired is set to be exlcluded, set the database to whatever is currently
21
+ # next in line in the schema search path.
22
+ database = if self.class.excluded_subdomains.include?(request_subdomain)
23
+ nil
24
+ else
25
+ request_subdomain
26
+ end
10
27
 
11
28
  database.present? && database || nil
12
29
  end
@@ -32,4 +49,4 @@ module Apartment
32
49
  end
33
50
  end
34
51
  end
35
- end
52
+ end
@@ -1,5 +1,6 @@
1
- module Apartment
1
+ require 'apartment/database'
2
2
 
3
+ module Apartment
3
4
  module Migrator
4
5
 
5
6
  extend self
@@ -1,4 +1,6 @@
1
1
  require 'rails'
2
+ require 'apartment/database'
3
+ require 'apartment/reloader'
2
4
 
3
5
  module Apartment
4
6
  class Railtie < Rails::Railtie
@@ -50,8 +52,6 @@ module Apartment
50
52
  console do
51
53
  require 'apartment/console'
52
54
  end
53
-
54
55
  end
55
-
56
56
  end
57
57
  end
@@ -1,5 +1,4 @@
1
1
  module Apartment
2
-
3
2
  class Reloader
4
3
 
5
4
  # Middleware used in development to init Apartment for each request
@@ -18,7 +17,5 @@ module Apartment
18
17
  Database.init
19
18
  @app.call(env)
20
19
  end
21
-
22
20
  end
23
-
24
21
  end
@@ -1,3 +1,3 @@
1
1
  module Apartment
2
- VERSION = "0.22.1"
3
- end
2
+ VERSION = "0.23.0"
3
+ end
@@ -1,3 +1,5 @@
1
+ require 'apartment/migrator'
2
+
1
3
  apartment_namespace = namespace :apartment do
2
4
 
3
5
  desc "Create all multi-tenant databases"
@@ -3,10 +3,8 @@ if defined?(JRUBY_VERSION)
3
3
  require 'spec_helper'
4
4
  require 'lib/apartment/adapters/jdbc_mysql_adapter'
5
5
 
6
- describe Apartment::Adapters::JDBCMysqlAdapter do
6
+ describe Apartment::Adapters::JDBCMysqlAdapter, database: :mysql do
7
7
 
8
-
9
- let(:config) { Apartment::Test.config['connections']['mysql'] }
10
8
  subject { Apartment::Database.jdbc_mysql_adapter config.symbolize_keys }
11
9
 
12
10
  def database_names
@@ -3,10 +3,8 @@ if defined?(JRUBY_VERSION)
3
3
  require 'spec_helper'
4
4
  require 'lib/apartment/adapters/jdbc_postgresql_adapter'
5
5
 
6
- describe Apartment::Adapters::JDBCPostgresqlAdapter do
6
+ describe Apartment::Adapters::JDBCPostgresqlAdapter, database: :postgresql do
7
7
 
8
-
9
- let(:config) { Apartment::Test.config['connections']['postgresql'] }
10
8
  subject { Apartment::Database.jdbc_postgresql_adapter config.symbolize_keys }
11
9
 
12
10
  context "using schemas" do
@@ -1,10 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'apartment/adapters/mysql2_adapter'
3
3
 
4
- describe Apartment::Adapters::Mysql2Adapter do
4
+ describe Apartment::Adapters::Mysql2Adapter, database: :mysql do
5
5
  unless defined?(JRUBY_VERSION)
6
6
 
7
- let(:config){ Apartment::Test.config['connections']['mysql'].symbolize_keys }
8
7
  subject(:adapter){ Apartment::Database.mysql2_adapter config }
9
8
 
10
9
  def database_names
@@ -1,10 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'apartment/adapters/postgresql_adapter'
3
3
 
4
- describe Apartment::Adapters::PostgresqlAdapter do
4
+ describe Apartment::Adapters::PostgresqlAdapter, database: :postgresql do
5
5
  unless defined?(JRUBY_VERSION)
6
6
 
7
- let(:config){ Apartment::Test.config['connections']['postgresql'].symbolize_keys }
8
7
  subject{ Apartment::Database.postgresql_adapter config }
9
8
 
10
9
  context "using schemas" do
@@ -1,10 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'apartment/adapters/sqlite3_adapter'
3
3
 
4
- describe Apartment::Adapters::Sqlite3Adapter do
4
+ describe Apartment::Adapters::Sqlite3Adapter, database: :sqlite do
5
5
  unless defined?(JRUBY_VERSION)
6
6
 
7
- let(:config){ Apartment::Test.config['connections']['sqlite'].symbolize_keys }
8
7
  subject{ Apartment::Database.sqlite3_adapter config }
9
8
 
10
9
  context "using connections" do
@@ -1,14 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Apartment::Database do
4
- context "using mysql" do
5
- # See apartment.yml file in dummy app config
6
-
7
- let(:config){ Apartment::Test.config['connections']['mysql'].symbolize_keys }
4
+ context "using mysql", database: :mysql do
8
5
 
9
6
  before do
10
- ActiveRecord::Base.establish_connection config
11
- Apartment::Test.load_schema # load the Rails schema in the public db schema
12
7
  subject.stub(:config).and_return config # Use mysql database config for this test
13
8
  end
14
9
 
@@ -26,25 +21,22 @@ describe Apartment::Database do
26
21
  # TODO this doesn't belong here, but there aren't integration tests currently for mysql
27
22
  # where to put???
28
23
  describe "#exception recovery", :type => :request do
29
- let(:database1){ Apartment::Test.next_db }
30
-
31
24
  before do
32
25
  subject.reload!
33
- subject.create database1
26
+ subject.create db1
34
27
  end
35
- after{ subject.drop database1 }
36
-
37
- it "should recover from incorrect database" do
38
- session = Capybara::Session.new(:rack_test, Capybara.app)
39
- session.visit("http://#{database1}.com")
40
- expect {
41
- session.visit("http://this-database-should-not-exist.com")
42
- }.to raise_error
43
- session.visit("http://#{database1}.com")
44
- end
45
-
28
+ after{ subject.drop db1 }
29
+
30
+ # it "should recover from incorrect database" do
31
+ # session = Capybara::Session.new(:rack_test, Capybara.app)
32
+ # session.visit("http://#{db1}.com")
33
+ # expect {
34
+ # session.visit("http://this-database-should-not-exist.com")
35
+ # }.to raise_error
36
+ # session.visit("http://#{db1}.com")
37
+ # end
46
38
  end
47
-
39
+
48
40
  context "with prefix and schemas" do
49
41
  describe "#create" do
50
42
  before do
@@ -52,11 +44,12 @@ describe Apartment::Database do
52
44
  config.prepend_environment = true
53
45
  config.use_schemas = true
54
46
  end
47
+
55
48
  subject.reload!(config) # switch to Mysql2SchemaAdapter
56
49
  end
57
-
50
+
58
51
  after { subject.drop "db_with_prefix" rescue nil }
59
-
52
+
60
53
  it "should create a new database" do
61
54
  subject.create "db_with_prefix"
62
55
  end
@@ -64,18 +57,9 @@ describe Apartment::Database do
64
57
  end
65
58
  end
66
59
 
67
- context "using postgresql" do
68
-
69
- # See apartment.yml file in dummy app config
70
-
71
- let(:config){ Apartment::Test.config['connections']['postgresql'].symbolize_keys }
72
- let(:database){ Apartment::Test.next_db }
73
- let(:database2){ Apartment::Test.next_db }
74
-
60
+ context "using postgresql", database: :postgresql do
75
61
  before do
76
62
  Apartment.use_schemas = true
77
- ActiveRecord::Base.establish_connection config
78
- Apartment::Test.load_schema # load the Rails schema in the public db schema
79
63
  subject.stub(:config).and_return config # Use postgresql database config for this test
80
64
  end
81
65
 
@@ -90,7 +74,7 @@ describe Apartment::Database do
90
74
  end
91
75
 
92
76
  it "should raise exception with invalid adapter specified" do
93
- subject.stub(:config).and_return config.merge(:adapter => 'unkown')
77
+ subject.stub(:config).and_return config.merge(:adapter => 'unknown')
94
78
 
95
79
  expect {
96
80
  Apartment::Database.adapter
@@ -98,13 +82,14 @@ describe Apartment::Database do
98
82
  end
99
83
 
100
84
  context "threadsafety" do
101
- before { subject.create database }
85
+ before { subject.create db1 }
86
+ after { subject.drop db1 }
102
87
 
103
88
  it 'has a threadsafe adapter' do
104
- subject.switch(database)
89
+ subject.switch(db1)
105
90
  thread = Thread.new { subject.current_database.should == Apartment.default_schema }
106
91
  thread.join
107
- subject.current_database.should == database
92
+ subject.current_database.should == db1
108
93
  end
109
94
  end
110
95
  end
@@ -117,14 +102,14 @@ describe Apartment::Database do
117
102
  config.use_schemas = true
118
103
  config.seed_after_create = true
119
104
  end
120
- subject.create database
105
+ subject.create db1
121
106
  end
122
107
 
123
- after{ subject.drop database }
108
+ after{ subject.drop db1 }
124
109
 
125
110
  describe "#create" do
126
111
  it "should seed data" do
127
- subject.switch database
112
+ subject.switch db1
128
113
  User.count.should be > 0
129
114
  end
130
115
  end
@@ -135,20 +120,20 @@ describe Apartment::Database do
135
120
 
136
121
  context "creating models" do
137
122
 
138
- before{ subject.create database2 }
139
- after{ subject.drop database2 }
123
+ before{ subject.create db2 }
124
+ after{ subject.drop db2 }
140
125
 
141
126
  it "should create a model instance in the current schema" do
142
- subject.switch database2
127
+ subject.switch db2
143
128
  db2_count = User.count + x.times{ User.create }
144
129
 
145
- subject.switch database
130
+ subject.switch db1
146
131
  db_count = User.count + x.times{ User.create }
147
132
 
148
- subject.switch database2
133
+ subject.switch db2
149
134
  User.count.should == db2_count
150
135
 
151
- subject.switch database
136
+ subject.switch db1
152
137
  User.count.should == db_count
153
138
  end
154
139
  end
@@ -166,17 +151,14 @@ describe Apartment::Database do
166
151
  subject.reset # ensure we're on public schema
167
152
  count = Company.count + x.times{ Company.create }
168
153
 
169
- subject.switch database
154
+ subject.switch db1
170
155
  x.times{ Company.create }
171
156
  Company.count.should == count + x
172
157
  subject.reset
173
158
  Company.count.should == count + x
174
159
  end
175
160
  end
176
-
177
161
  end
178
-
179
162
  end
180
-
181
163
  end
182
164
  end
@@ -1,5 +1,3 @@
1
1
  class User < ActiveRecord::Base
2
- include Apartment::Delayed::Job::Hooks
3
- def perform; end
4
2
  # Dummy models
5
3
  end
@@ -14,6 +14,8 @@ module Dummy
14
14
  # Settings in config/environments/* take precedence over those specified here.
15
15
  # Application configuration should go into files in config/initializers
16
16
  # -- all .rb files in that directory are automatically loaded.
17
+ require 'apartment/elevators/subdomain'
18
+ require 'apartment/elevators/domain'
17
19
 
18
20
  config.middleware.use 'Apartment::Elevators::Subdomain'
19
21
  config.middleware.use 'Apartment::Elevators::Domain'
@@ -6,6 +6,8 @@ Dummy::Application.configure do
6
6
  # since you don't have to restart the webserver when you make code changes.
7
7
  config.cache_classes = false
8
8
 
9
+ config.eager_load = false
10
+
9
11
  # Log error messages when you accidentally call methods on nil.
10
12
  config.whiny_nils = true
11
13
 
@@ -5,6 +5,8 @@ Dummy::Application.configure do
5
5
  # Code is not reloaded between requests
6
6
  config.cache_classes = true
7
7
 
8
+ config.eager_load = true
9
+
8
10
  # Full error reports are disabled and caching is turned on
9
11
  config.consider_all_requests_local = false
10
12
  config.action_controller.perform_caching = true
@@ -7,8 +7,7 @@ Dummy::Application.configure do
7
7
  # and recreated between test runs. Don't rely on the data there!
8
8
  config.cache_classes = true
9
9
 
10
- # Log error messages when you accidentally call methods on nil.
11
- config.whiny_nils = true
10
+ config.eager_load = false
12
11
 
13
12
  # Show full error reports and disable caching
14
13
  config.consider_all_requests_local = true
@@ -1,4 +1,4 @@
1
1
  Apartment.configure do |config|
2
2
  config.excluded_models = ["Company"]
3
- config.database_names = lambda{ Company.scoped.collect(&:database) }
3
+ config.database_names = lambda{ Company.pluck(:database) }
4
4
  end
@@ -1,8 +1,5 @@
1
1
  def create_users
2
- 3.times do |x|
3
- user = User.find_or_initialize_by_name "Some User #{x}"
4
- user.save
5
- end
2
+ 3.times {|x| User.where(name: "Some User #{x}").first_or_create! }
6
3
  end
7
4
 
8
5
  create_users
@@ -4,17 +4,17 @@ shared_examples_for "an apartment elevator" do
4
4
 
5
5
  context "single request" do
6
6
  it "should switch the db" do
7
- ActiveRecord::Base.connection.schema_search_path.should_not == %{"#{database1}"}
7
+ ActiveRecord::Base.connection.schema_search_path.should_not == %{"#{db1}"}
8
8
 
9
9
  visit(domain1)
10
- ActiveRecord::Base.connection.schema_search_path.should == %{"#{database1}"}
10
+ ActiveRecord::Base.connection.schema_search_path.should == %{"#{db1}"}
11
11
  end
12
12
  end
13
13
 
14
14
  context "simultaneous requests" do
15
15
 
16
- let!(:c1_user_count) { api.process(database1){ (2 + rand(2)).times{ User.create } } }
17
- let!(:c2_user_count) { api.process(database2){ (c1_user_count + 2).times{ User.create } } }
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
18
 
19
19
  it "should fetch the correct user count for each session based on the elevator processor" do
20
20
  visit(domain1)