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