apartment 0.22.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
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)