apartment 0.21.1 → 0.22.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.
- checksums.yaml +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +1 -1
- data/HISTORY.md +11 -0
- data/README.md +15 -1
- data/TODO.md +52 -0
- data/lib/apartment.rb +1 -0
- data/lib/apartment/adapters/mysql2_adapter.rb +2 -2
- data/lib/apartment/adapters/postgresql_adapter.rb +3 -3
- data/lib/apartment/elevators/domain.rb +1 -1
- data/lib/apartment/elevators/host_hash.rb +20 -0
- data/lib/apartment/version.rb +1 -1
- data/lib/tasks/apartment.rake +52 -17
- data/spec/adapters/jdbc_postgresql_adapter_spec.rb +2 -2
- data/spec/adapters/postgresql_adapter_spec.rb +2 -2
- data/spec/database_spec.rb +18 -0
- data/spec/examples/elevator_examples.rb +2 -2
- data/spec/examples/schema_adapter_examples.rb +15 -15
- data/spec/unit/middleware/host_hash_elevator_spec.rb +26 -0
- data/spec/unit/migrator_spec.rb +7 -7
- metadata +17 -26
- data/.rvmrc +0 -1
- data/lib/apartment/sidekiq/client/database_middleware.rb +0 -12
- data/lib/apartment/sidekiq/server/database_middleware.rb +0 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 633c827866f4356529e375c9fe6b1b2f8886dbf3
|
4
|
+
data.tar.gz: 8b568ba43bbc49eb726ecc439b314b9c19c73ff3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 96084d067de04ce41892a639887c7ce2d248e556c1624879721f0bf4529348cf504f04c408f7f82a6cbb17366078d48b542bf75f5b569cd32f85b684ff380739
|
7
|
+
data.tar.gz: 1173968bbe02e081870bba50bbbab33775e16a6f42e213b34bb15b0a47929fe1d8dcc8ca83eca243669ded99a8dd9a52d1cf46e49d995fb62209b0f877d71336
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
apartment
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0
|
data/.travis.yml
CHANGED
data/HISTORY.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# 0.22.0
|
2
|
+
* June 9, 2013
|
3
|
+
|
4
|
+
- Numerous bug fixes:
|
5
|
+
- Mysql reset could connect to wrong database [eric88]
|
6
|
+
- Postgresql schema names weren't quoted properly [gdott9]
|
7
|
+
- Fixed error message on SchemaNotFound in `process`
|
8
|
+
- HostHash elevator allows mapping host based on hash contents [gdott9]
|
9
|
+
- Official Sidekiq support with the [apartment-sidekiq gem](https://github.com/influitive/apartment-sidekiq)
|
10
|
+
|
11
|
+
|
1
12
|
# 0.21.1
|
2
13
|
* May 31, 2013
|
3
14
|
|
data/README.md
CHANGED
@@ -94,6 +94,18 @@ module My Application
|
|
94
94
|
end
|
95
95
|
```
|
96
96
|
|
97
|
+
**Switch on full host using a hash**
|
98
|
+
To switch based on full host with a hash to find corresponding database name use the following:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
# application.rb
|
102
|
+
module My Application
|
103
|
+
class Application < Rails::Application
|
104
|
+
config.middleware.use 'Apartment::Elevators::HostHash', {'example.com' => 'example_database'}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
97
109
|
**Custom Elevator**
|
98
110
|
A Generic Elevator exists that allows you to pass a `Proc` (or anything that responds to `call`) to the middleware. This Object will be passed in an `ActionDispatch::Request` object when called for you to do your magic. Apartment will use the return value of this proc to switch to the appropriate database. Use like so:
|
99
111
|
|
@@ -281,7 +293,7 @@ All jobs *must* stored in the global (public) namespace, so add it to the list o
|
|
281
293
|
config.excluded_models = ["Delayed::Job"]
|
282
294
|
```
|
283
295
|
|
284
|
-
##
|
296
|
+
## Contributing
|
285
297
|
|
286
298
|
* In both `spec/dummy/config` and `spec/config`, you will see `database.yml.sample` files
|
287
299
|
* Copy them into the same directory but with the name `database.yml`
|
@@ -290,6 +302,8 @@ config.excluded_models = ["Delayed::Job"]
|
|
290
302
|
* Please issue pull requests to the `development` branch. All development happens here, master is used for releases
|
291
303
|
* Ensure that your code is accompanied with tests. No code will be merged without tests
|
292
304
|
|
305
|
+
* If you're looking to help, check out the TODO file for some upcoming changes I'd like to implement in Apartment.
|
306
|
+
|
293
307
|
## License
|
294
308
|
|
295
309
|
Apartment is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
data/TODO.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Apartment TODOs
|
2
|
+
|
3
|
+
### Below is a list of tasks in the approximate order to be completed of for Apartment
|
4
|
+
### Any help along the way is greatly appreciated (on any items, not particularly in order)
|
5
|
+
|
6
|
+
1. Apartment was originally written (and TDD'd) with just Postgresql in mind. Different adapters were added at a later date.
|
7
|
+
As such, the test suite is a bit of a mess. There's no formal structure for fully integration testing all adapters to ensure
|
8
|
+
proper quality and prevent regressions.
|
9
|
+
|
10
|
+
There's also a test order dependency as some tests run assuming a db connection and if that test randomly ran before a previous
|
11
|
+
one that makes the connection, it would fail.
|
12
|
+
|
13
|
+
I'm proposing the first thing to be done is to write up a standard, high livel integration test case that can be applied to all adapters
|
14
|
+
and makes no assumptions about implementation. It should ensure that each adapter conforms to the Apartment Interface and CRUD's properly.
|
15
|
+
It would be nice if a user can 'register' an adapter such that it would automatically be tested (nice to have). Otherwise one could just use
|
16
|
+
a shared behaviour to run through all of this.
|
17
|
+
|
18
|
+
Then, I'd like to see all of the implementation specific tests just in their own test file for each adapter (ie the postgresql schema adapter
|
19
|
+
checks a lot of things with `schema_search_path`)
|
20
|
+
|
21
|
+
This should ensure that going forward nothing breaks, and we should *ideally* be able to randomize the test order
|
22
|
+
|
23
|
+
2. `Apartment::Database` is the wrong abstraction. When dealing with a multi-tenanted system, users shouldn't thing about 'Databases', they should
|
24
|
+
think about Tenants. I proprose that we deprecate the `Apartment::Database` constant in favour of `Apartment::Tenant` for a nicer abstraction. See
|
25
|
+
http://myronmars.to/n/dev-blog/2011/09/deprecating-constants-and-classes-in-ruby for ideas on how to achieve this.
|
26
|
+
|
27
|
+
3. `Delayed::Job` has proven to be an absolute P.I.T.A. It's YAML hacks are beyond reproach and require further hacks in order to work properly.
|
28
|
+
I want to completely remove the Delayed::Job dependency from Apartment and make an `apartment-delayed-job` gem that can be worked on independently
|
29
|
+
(and hopefully eventually deprecated). To this end, I've started an `apartment-sidekiq` gem and would love to see an `apartment-resque` gem to deal
|
30
|
+
with those background workers from a multi-tenant perspective also.
|
31
|
+
|
32
|
+
4. Apartment::Database.process should be deprecated in favour of just passing an optional block to `switch`
|
33
|
+
|
34
|
+
5. Migrations right now can be a bit of a pain. Apartment currently migrates a single tenant completely up to date, then goes onto the next. If one of these
|
35
|
+
migrations fails on a tenant, the previous one does NOT get reverted and leaves you in an awkward state. Ideally we'd want to wrap all of the migrations in
|
36
|
+
a transaction so if one fails, the whole thing reverts. Once we can ensure an all-or-nothing approach to migrations, we can optimize the migration strategy
|
37
|
+
to not even iterate over the tenants if there are no migrations to run on public. I also thought id would be nice to provide an optional file to require in one's
|
38
|
+
Rakefile such that it would override `db:migrate` to do `apartment:migrate`. That way people don't have to remember to use a different task and there's no confusion.
|
39
|
+
|
40
|
+
6. Apartment has be come one of the most popular/robust Multi-tenant gems for Rails, but it still doesn't work for everyone's use case. It's fairly limited
|
41
|
+
in implementation to either schema based (ie postgresql schemas) or connection based. I'd like to abstract out these implementation details such that one
|
42
|
+
could write a pluggable strategy for Apartment and choose it based on a config selection (something like `config.strategy = :schema`). The next implementation
|
43
|
+
I'd like to see is a scoped based approach that uses a `tenant_id` scoping on all records for multi-tenancy. This is probably the most popular multi-tenant approach
|
44
|
+
and is db independent and really the simplest mechanism for a type of multi-tenancy.
|
45
|
+
|
46
|
+
7. Right now excluded tables still live in all tenanted environments. This is basically because it doesn't matter if they're there, we always query from the public.
|
47
|
+
It's a bit of an annoyance though and confuses lots of people. I'd love to see only tenanted tables in the tenants and only excluded tables in the public tenant.
|
48
|
+
This will be hard because Rails uses public to generate schema.rb. One idea is to have an `excluded` schema that holds all the excluded models and the public can
|
49
|
+
maintain everything.
|
50
|
+
|
51
|
+
8. This one is pretty lofty, but I'd also like to abstract out the fact that Apartment uses ActiveRecord. With the new DataMapper coming out soon and other popular
|
52
|
+
DBMS's (ie. mongo, couch etc...), it'd be nice if Apartment could be the de-facto interface for multi-tenancy on these systems.
|
data/lib/apartment.rb
CHANGED
@@ -80,6 +80,7 @@ module Apartment
|
|
80
80
|
autoload :Subdomain, 'apartment/elevators/subdomain'
|
81
81
|
autoload :FirstSubdomain, 'apartment/elevators/first_subdomain'
|
82
82
|
autoload :Domain, 'apartment/elevators/domain'
|
83
|
+
autoload :HostHash, 'apartment/elevators/host_hash'
|
83
84
|
end
|
84
85
|
|
85
86
|
module Delayed
|
@@ -41,7 +41,7 @@ module Apartment
|
|
41
41
|
# Reset current_database to the default_database
|
42
42
|
#
|
43
43
|
def reset
|
44
|
-
|
44
|
+
Apartment.connection.execute "use #{default_database}"
|
45
45
|
end
|
46
46
|
|
47
47
|
# Set the table_name to always use the default database for excluded models
|
@@ -57,7 +57,7 @@ module Apartment
|
|
57
57
|
def connect_to_new(database)
|
58
58
|
return reset if database.nil?
|
59
59
|
|
60
|
-
Apartment.connection.execute "use #{database}"
|
60
|
+
Apartment.connection.execute "use #{environmentify(database)}"
|
61
61
|
|
62
62
|
rescue ActiveRecord::StatementInvalid
|
63
63
|
Apartment::Database.reset
|
@@ -79,7 +79,7 @@ module Apartment
|
|
79
79
|
Apartment.connection.schema_search_path = full_search_path
|
80
80
|
|
81
81
|
rescue *rescuable_exceptions
|
82
|
-
raise SchemaNotFound, "One of the following schema(s) is invalid: #{full_search_path}"
|
82
|
+
raise SchemaNotFound, "One of the following schema(s) is invalid: #{database}, #{full_search_path}"
|
83
83
|
end
|
84
84
|
|
85
85
|
# Create the new schema
|
@@ -96,8 +96,8 @@ module Apartment
|
|
96
96
|
# Generate the final search path to set including persistent_schemas
|
97
97
|
#
|
98
98
|
def full_search_path
|
99
|
-
persistent_schemas = Apartment.persistent_schemas.join(', ')
|
100
|
-
@current_database.to_s + (persistent_schemas.empty? ? "" : ", #{persistent_schemas}")
|
99
|
+
persistent_schemas = Apartment.persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
|
100
|
+
%{"#{@current_database.to_s}"} + (persistent_schemas.empty? ? "" : ", #{persistent_schemas}")
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Apartment
|
2
|
+
module Elevators
|
3
|
+
# Provides a rack based db switching solution based on hosts
|
4
|
+
# Uses a hash to find the corresponding database name for the host
|
5
|
+
#
|
6
|
+
class HostHash < Generic
|
7
|
+
def initialize(app, hash = {}, processor = nil)
|
8
|
+
super app, processor
|
9
|
+
@hash = hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_database_name(request)
|
13
|
+
raise DatabaseNotFound,
|
14
|
+
"Cannot find database for host #{request.host}" unless @hash.has_key?(request.host)
|
15
|
+
|
16
|
+
@hash[request.host]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/apartment/version.rb
CHANGED
data/lib/tasks/apartment.rake
CHANGED
@@ -1,21 +1,41 @@
|
|
1
1
|
apartment_namespace = namespace :apartment do
|
2
2
|
|
3
|
+
desc "Create all multi-tenant databases"
|
4
|
+
task :create => 'db:migrate' do
|
5
|
+
database_names.each do |db|
|
6
|
+
begin
|
7
|
+
puts("Creating #{db} database")
|
8
|
+
quietly { Apartment::Database.create(db) }
|
9
|
+
rescue Apartment::DatabaseExists, Apartment::SchemaExists => e
|
10
|
+
puts e.message
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
3
15
|
desc "Migrate all multi-tenant databases"
|
4
16
|
task :migrate => 'db:migrate' do
|
5
17
|
|
6
|
-
|
7
|
-
|
8
|
-
|
18
|
+
database_names.each do |db|
|
19
|
+
begin
|
20
|
+
puts("Migrating #{db} database")
|
21
|
+
Apartment::Migrator.migrate db
|
22
|
+
rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
|
23
|
+
puts e.message
|
24
|
+
end
|
9
25
|
end
|
10
26
|
end
|
11
27
|
|
12
28
|
desc "Seed all multi-tenant databases"
|
13
29
|
task :seed => 'db:seed' do
|
14
30
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
Apartment::Database.
|
31
|
+
database_names.each do |db|
|
32
|
+
begin
|
33
|
+
puts("Seeding #{db} database")
|
34
|
+
Apartment::Database.process(db) do
|
35
|
+
Apartment::Database.seed
|
36
|
+
end
|
37
|
+
rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
|
38
|
+
puts e.message
|
19
39
|
end
|
20
40
|
end
|
21
41
|
end
|
@@ -24,9 +44,13 @@ apartment_namespace = namespace :apartment do
|
|
24
44
|
task :rollback => 'db:rollback' do
|
25
45
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
26
46
|
|
27
|
-
|
28
|
-
|
29
|
-
|
47
|
+
database_names.each do |db|
|
48
|
+
begin
|
49
|
+
puts("Rolling back #{db} database")
|
50
|
+
Apartment::Migrator.rollback db, step
|
51
|
+
rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
|
52
|
+
puts e.message
|
53
|
+
end
|
30
54
|
end
|
31
55
|
end
|
32
56
|
|
@@ -37,9 +61,13 @@ apartment_namespace = namespace :apartment do
|
|
37
61
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
38
62
|
raise 'VERSION is required' unless version
|
39
63
|
|
40
|
-
|
41
|
-
|
42
|
-
|
64
|
+
database_names.each do |db|
|
65
|
+
begin
|
66
|
+
puts("Migrating #{db} database up")
|
67
|
+
Apartment::Migrator.run :up, db, version
|
68
|
+
rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
|
69
|
+
puts e.message
|
70
|
+
end
|
43
71
|
end
|
44
72
|
end
|
45
73
|
|
@@ -48,9 +76,13 @@ apartment_namespace = namespace :apartment do
|
|
48
76
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
49
77
|
raise 'VERSION is required' unless version
|
50
78
|
|
51
|
-
|
52
|
-
|
53
|
-
|
79
|
+
database_names.each do |db|
|
80
|
+
begin
|
81
|
+
puts("Migrating #{db} database down")
|
82
|
+
Apartment::Migrator.run :down, db, version
|
83
|
+
rescue Apartment::DatabaseNotFound, Apartment::SchemaNotFound => e
|
84
|
+
puts e.message
|
85
|
+
end
|
54
86
|
end
|
55
87
|
end
|
56
88
|
|
@@ -67,4 +99,7 @@ apartment_namespace = namespace :apartment do
|
|
67
99
|
|
68
100
|
end
|
69
101
|
|
70
|
-
|
102
|
+
def database_names
|
103
|
+
ENV['DB'] ? ENV['DB'].split(',').map { |s| s.strip } : Apartment.database_names
|
104
|
+
end
|
105
|
+
end
|
@@ -18,7 +18,7 @@ if defined?(JRUBY_VERSION)
|
|
18
18
|
ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect { |row| row['nspname'] }
|
19
19
|
end
|
20
20
|
|
21
|
-
let(:default_database) { subject.process { ActiveRecord::Base.connection.schema_search_path } }
|
21
|
+
let(:default_database) { subject.process { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } }
|
22
22
|
|
23
23
|
it_should_behave_like "a generic apartment adapter"
|
24
24
|
it_should_behave_like "a schema based apartment adapter"
|
@@ -40,4 +40,4 @@ if defined?(JRUBY_VERSION)
|
|
40
40
|
|
41
41
|
end
|
42
42
|
end
|
43
|
-
end
|
43
|
+
end
|
@@ -16,7 +16,7 @@ describe Apartment::Adapters::PostgresqlAdapter do
|
|
16
16
|
ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect { |row| row['nspname'] }
|
17
17
|
end
|
18
18
|
|
19
|
-
let(:default_database) { subject.process { ActiveRecord::Base.connection.schema_search_path } }
|
19
|
+
let(:default_database) { subject.process { ActiveRecord::Base.connection.schema_search_path.gsub('"', '') } }
|
20
20
|
|
21
21
|
it_should_behave_like "a generic apartment adapter"
|
22
22
|
it_should_behave_like "a schema based apartment adapter"
|
@@ -37,4 +37,4 @@ describe Apartment::Adapters::PostgresqlAdapter do
|
|
37
37
|
it_should_behave_like "a connection based apartment adapter"
|
38
38
|
end
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
data/spec/database_spec.rb
CHANGED
@@ -44,6 +44,24 @@ describe Apartment::Database do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
end
|
47
|
+
|
48
|
+
context "with prefix and schemas" do
|
49
|
+
describe "#create" do
|
50
|
+
before do
|
51
|
+
Apartment.configure do |config|
|
52
|
+
config.prepend_environment = true
|
53
|
+
config.use_schemas = true
|
54
|
+
end
|
55
|
+
subject.reload!(config) # switch to Mysql2SchemaAdapter
|
56
|
+
end
|
57
|
+
|
58
|
+
after { subject.drop "db_with_prefix" rescue nil }
|
59
|
+
|
60
|
+
it "should create a new database" do
|
61
|
+
subject.create "db_with_prefix"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
47
65
|
end
|
48
66
|
|
49
67
|
context "using postgresql" do
|
@@ -4,10 +4,10 @@ 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 == %{"#{database1}"}
|
8
8
|
|
9
9
|
visit(domain1)
|
10
|
-
ActiveRecord::Base.connection.schema_search_path.should == database1
|
10
|
+
ActiveRecord::Base.connection.schema_search_path.should == %{"#{database1}"}
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -48,11 +48,11 @@ shared_examples_for "a schema based apartment adapter" do
|
|
48
48
|
|
49
49
|
subject.create(schema2) do
|
50
50
|
@count = User.count
|
51
|
-
connection.schema_search_path.should start_with schema2
|
51
|
+
connection.schema_search_path.should start_with %{"#{schema2}"}
|
52
52
|
User.create
|
53
53
|
end
|
54
54
|
|
55
|
-
connection.schema_search_path.should_not start_with schema2
|
55
|
+
connection.schema_search_path.should_not start_with %{"#{schema2}"}
|
56
56
|
|
57
57
|
subject.process(schema2){ User.count.should == @count + 1 }
|
58
58
|
end
|
@@ -96,13 +96,13 @@ shared_examples_for "a schema based apartment adapter" do
|
|
96
96
|
describe "#process" do
|
97
97
|
it "should connect" do
|
98
98
|
subject.process(schema1) do
|
99
|
-
connection.schema_search_path.should start_with schema1
|
99
|
+
connection.schema_search_path.should start_with %{"#{schema1}"}
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should reset" do
|
104
104
|
subject.process(schema1)
|
105
|
-
connection.schema_search_path.should start_with public_schema
|
105
|
+
connection.schema_search_path.should start_with %{"#{public_schema}"}
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -110,14 +110,14 @@ shared_examples_for "a schema based apartment adapter" do
|
|
110
110
|
it "should reset connection" do
|
111
111
|
subject.switch(schema1)
|
112
112
|
subject.reset
|
113
|
-
connection.schema_search_path.should start_with public_schema
|
113
|
+
connection.schema_search_path.should start_with %{"#{public_schema}"}
|
114
114
|
end
|
115
115
|
|
116
116
|
context "with default_schema", :default_schema => true do
|
117
117
|
it "should reset to the default schema" do
|
118
118
|
subject.switch(schema1)
|
119
119
|
subject.reset
|
120
|
-
connection.schema_search_path.should start_with default_schema
|
120
|
+
connection.schema_search_path.should start_with %{"#{default_schema}"}
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
@@ -128,13 +128,13 @@ shared_examples_for "a schema based apartment adapter" do
|
|
128
128
|
end
|
129
129
|
|
130
130
|
it "maintains the persistent schemas in the schema_search_path" do
|
131
|
-
connection.schema_search_path.should end_with persistent_schemas.join(', ')
|
131
|
+
connection.schema_search_path.should end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
|
132
132
|
end
|
133
133
|
|
134
134
|
context "with default_schema", :default_schema => true do
|
135
135
|
it "prioritizes the switched schema to front of schema_search_path" do
|
136
136
|
subject.reset # need to re-call this as the default_schema wasn't set at the time that the above reset ran
|
137
|
-
connection.schema_search_path.should start_with default_schema
|
137
|
+
connection.schema_search_path.should start_with %{"#{default_schema}"}
|
138
138
|
end
|
139
139
|
end
|
140
140
|
end
|
@@ -143,12 +143,12 @@ shared_examples_for "a schema based apartment adapter" do
|
|
143
143
|
describe "#switch" do
|
144
144
|
it "should connect to new schema" do
|
145
145
|
subject.switch(schema1)
|
146
|
-
connection.schema_search_path.should start_with schema1
|
146
|
+
connection.schema_search_path.should start_with %{"#{schema1}"}
|
147
147
|
end
|
148
148
|
|
149
149
|
it "should reset connection if database is nil" do
|
150
150
|
subject.switch
|
151
|
-
connection.schema_search_path.should == public_schema
|
151
|
+
connection.schema_search_path.should == %{"#{public_schema}"}
|
152
152
|
end
|
153
153
|
|
154
154
|
it "should raise an error if schema is invalid" do
|
@@ -166,7 +166,7 @@ shared_examples_for "a schema based apartment adapter" do
|
|
166
166
|
subject.switch(db)
|
167
167
|
}.to_not raise_error
|
168
168
|
|
169
|
-
connection.schema_search_path.should start_with db.to_s
|
169
|
+
connection.schema_search_path.should start_with %{"#{db.to_s}"}
|
170
170
|
end
|
171
171
|
|
172
172
|
after{ subject.drop(db) }
|
@@ -182,7 +182,7 @@ shared_examples_for "a schema based apartment adapter" do
|
|
182
182
|
end
|
183
183
|
|
184
184
|
it "should still switch to the switched schema" do
|
185
|
-
connection.schema_search_path.should start_with schema1
|
185
|
+
connection.schema_search_path.should start_with %{"#{schema1}"}
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
@@ -191,11 +191,11 @@ shared_examples_for "a schema based apartment adapter" do
|
|
191
191
|
before{ subject.switch(schema1) }
|
192
192
|
|
193
193
|
it "maintains the persistent schemas in the schema_search_path" do
|
194
|
-
connection.schema_search_path.should end_with persistent_schemas.join(', ')
|
194
|
+
connection.schema_search_path.should end_with persistent_schemas.map { |schema| %{"#{schema}"} }.join(', ')
|
195
195
|
end
|
196
196
|
|
197
197
|
it "prioritizes the switched schema to front of schema_search_path" do
|
198
|
-
connection.schema_search_path.should start_with schema1
|
198
|
+
connection.schema_search_path.should start_with %{"#{schema1}"}
|
199
199
|
end
|
200
200
|
end
|
201
201
|
end
|
@@ -215,4 +215,4 @@ shared_examples_for "a schema based apartment adapter" do
|
|
215
215
|
end
|
216
216
|
end
|
217
217
|
end
|
218
|
-
end
|
218
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Apartment::Elevators::HostHash do
|
4
|
+
|
5
|
+
describe "#parse_database_name" do
|
6
|
+
it "parses the host for a domain name" do
|
7
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
|
8
|
+
elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
|
9
|
+
elevator.parse_database_name(request).should == 'example_database'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "raises DatabaseNotFound exception if there is no host" do
|
13
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => '')
|
14
|
+
elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
|
15
|
+
expect { elevator.parse_database_name(request) }.to raise_error(Apartment::DatabaseNotFound)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises DatabaseNotFound exception if there is no database associated to current host" do
|
19
|
+
request = ActionDispatch::Request.new('HTTP_HOST' => 'example2.com')
|
20
|
+
elevator = Apartment::Elevators::HostHash.new(nil, 'example.com' => 'example_database')
|
21
|
+
expect { elevator.parse_database_name(request) }.to raise_error(Apartment::DatabaseNotFound)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/spec/unit/migrator_spec.rb
CHANGED
@@ -34,8 +34,8 @@ describe Apartment::Migrator do
|
|
34
34
|
|
35
35
|
describe "#migrate" do
|
36
36
|
it "should connect to new db, then reset when done" do
|
37
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(schema_name).once
|
38
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(@original_schema).once
|
37
|
+
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
|
38
|
+
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
|
39
39
|
Apartment::Migrator.migrate(schema_name)
|
40
40
|
end
|
41
41
|
|
@@ -49,8 +49,8 @@ describe Apartment::Migrator do
|
|
49
49
|
context "up" do
|
50
50
|
|
51
51
|
it "should connect to new db, then reset when done" do
|
52
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(schema_name).once
|
53
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(@original_schema).once
|
52
|
+
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
|
53
|
+
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
|
54
54
|
Apartment::Migrator.run(:up, schema_name, version)
|
55
55
|
end
|
56
56
|
|
@@ -63,8 +63,8 @@ describe Apartment::Migrator do
|
|
63
63
|
describe "down" do
|
64
64
|
|
65
65
|
it "should connect to new db, then reset when done" do
|
66
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(schema_name).once
|
67
|
-
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(@original_schema).once
|
66
|
+
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{schema_name}"}).once
|
67
|
+
ActiveRecord::Base.connection.should_receive(:schema_search_path=).with(%{"#{@original_schema}"}).once
|
68
68
|
Apartment::Migrator.run(:down, schema_name, version)
|
69
69
|
end
|
70
70
|
|
@@ -86,4 +86,4 @@ describe Apartment::Migrator do
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
end
|
89
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apartment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.22.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ryan Brunner
|
@@ -10,38 +9,34 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-
|
12
|
+
date: 2013-07-09 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: activerecord
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - '>='
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: 3.1.2
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
|
-
- -
|
25
|
+
- - '>='
|
29
26
|
- !ruby/object:Gem::Version
|
30
27
|
version: 3.1.2
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: rack
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
|
-
- -
|
32
|
+
- - '>='
|
37
33
|
- !ruby/object:Gem::Version
|
38
34
|
version: 1.3.6
|
39
35
|
type: :runtime
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
|
-
- -
|
39
|
+
- - '>='
|
45
40
|
- !ruby/object:Gem::Version
|
46
41
|
version: 1.3.6
|
47
42
|
description: Apartment allows Rack applications to deal with database multitenancy
|
@@ -56,7 +51,8 @@ files:
|
|
56
51
|
- .gitignore
|
57
52
|
- .pryrc
|
58
53
|
- .rspec
|
59
|
-
- .
|
54
|
+
- .ruby-gemset
|
55
|
+
- .ruby-version
|
60
56
|
- .travis.yml
|
61
57
|
- .vagrant
|
62
58
|
- Cheffile
|
@@ -65,6 +61,7 @@ files:
|
|
65
61
|
- HISTORY.md
|
66
62
|
- README.md
|
67
63
|
- Rakefile
|
64
|
+
- TODO.md
|
68
65
|
- Vagrantfile
|
69
66
|
- apartment.gemspec
|
70
67
|
- circle.yml
|
@@ -87,12 +84,11 @@ files:
|
|
87
84
|
- lib/apartment/elevators/domain.rb
|
88
85
|
- lib/apartment/elevators/first_subdomain.rb
|
89
86
|
- lib/apartment/elevators/generic.rb
|
87
|
+
- lib/apartment/elevators/host_hash.rb
|
90
88
|
- lib/apartment/elevators/subdomain.rb
|
91
89
|
- lib/apartment/migrator.rb
|
92
90
|
- lib/apartment/railtie.rb
|
93
91
|
- lib/apartment/reloader.rb
|
94
|
-
- lib/apartment/sidekiq/client/database_middleware.rb
|
95
|
-
- lib/apartment/sidekiq/server/database_middleware.rb
|
96
92
|
- lib/apartment/version.rb
|
97
93
|
- lib/generators/apartment/install/USAGE
|
98
94
|
- lib/generators/apartment/install/install_generator.rb
|
@@ -161,39 +157,33 @@ files:
|
|
161
157
|
- spec/tasks/apartment_rake_spec.rb
|
162
158
|
- spec/unit/config_spec.rb
|
163
159
|
- spec/unit/middleware/domain_elevator_spec.rb
|
160
|
+
- spec/unit/middleware/host_hash_elevator_spec.rb
|
164
161
|
- spec/unit/middleware/subdomain_elevator_spec.rb
|
165
162
|
- spec/unit/migrator_spec.rb
|
166
163
|
- spec/unit/reloader_spec.rb
|
167
164
|
homepage: https://github.com/influitive/apartment
|
168
165
|
licenses:
|
169
166
|
- MIT
|
167
|
+
metadata: {}
|
170
168
|
post_install_message:
|
171
169
|
rdoc_options: []
|
172
170
|
require_paths:
|
173
171
|
- lib
|
174
172
|
required_ruby_version: !ruby/object:Gem::Requirement
|
175
|
-
none: false
|
176
173
|
requirements:
|
177
|
-
- -
|
174
|
+
- - '>='
|
178
175
|
- !ruby/object:Gem::Version
|
179
176
|
version: '0'
|
180
|
-
segments:
|
181
|
-
- 0
|
182
|
-
hash: 2789245529283699970
|
183
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
-
none: false
|
185
178
|
requirements:
|
186
|
-
- -
|
179
|
+
- - '>='
|
187
180
|
- !ruby/object:Gem::Version
|
188
181
|
version: '0'
|
189
|
-
segments:
|
190
|
-
- 0
|
191
|
-
hash: 2789245529283699970
|
192
182
|
requirements: []
|
193
183
|
rubyforge_project:
|
194
|
-
rubygems_version:
|
184
|
+
rubygems_version: 2.0.3
|
195
185
|
signing_key:
|
196
|
-
specification_version:
|
186
|
+
specification_version: 4
|
197
187
|
summary: A Ruby gem for managing database multitenancy
|
198
188
|
test_files:
|
199
189
|
- spec/adapters/jdbc_mysql_adapter_spec.rb
|
@@ -259,6 +249,7 @@ test_files:
|
|
259
249
|
- spec/tasks/apartment_rake_spec.rb
|
260
250
|
- spec/unit/config_spec.rb
|
261
251
|
- spec/unit/middleware/domain_elevator_spec.rb
|
252
|
+
- spec/unit/middleware/host_hash_elevator_spec.rb
|
262
253
|
- spec/unit/middleware/subdomain_elevator_spec.rb
|
263
254
|
- spec/unit/migrator_spec.rb
|
264
255
|
- spec/unit/reloader_spec.rb
|
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm --create ruby-1.9.3@apartment
|