apartment 0.14.3 → 0.14.4
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.
- data/HISTORY.md +5 -0
- data/README.md +29 -17
- data/apartment.gemspec +2 -1
- data/lib/apartment/delayed_job/active_record.rb +2 -2
- data/lib/apartment/delayed_job/hooks.rb +2 -1
- data/lib/apartment/version.rb +1 -1
- data/spec/adapters/postgresql_adapter_spec.rb +28 -28
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/config/boot.rb +4 -0
- data/spec/integration/delayed_job_integration_spec.rb +14 -1
- metadata +36 -25
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ Add the following to your Gemfile:
|
|
14
14
|
|
15
15
|
gem 'apartment'
|
16
16
|
|
17
|
-
That's all you need to set up the Apartment libraries. If you want to switch databases
|
17
|
+
That's all you need to set up the Apartment libraries. If you want to switch databases
|
18
18
|
on a per-user basis, look under "Usage - Switching databases per request", below.
|
19
19
|
|
20
20
|
> NOTE: If using [postgresl schemas](http://www.postgresql.org/docs/9.0/static/ddl-schemas.html) you must use:
|
@@ -31,11 +31,11 @@ you need to create a new database, you can run the following command:
|
|
31
31
|
|
32
32
|
Apartment::Database.create('database_name')
|
33
33
|
|
34
|
-
Apartment will create a new database in the following format: "_environment_\_database_name".
|
34
|
+
Apartment will create a new database in the following format: "_environment_\_database_name".
|
35
35
|
In the case of a sqlite database, this will be created in your 'db/migrate' folder. With
|
36
36
|
other databases, the database will be created as a new DB within the system.
|
37
37
|
|
38
|
-
When you create a new database, all migrations will be run against that database, so it will be
|
38
|
+
When you create a new database, all migrations will be run against that database, so it will be
|
39
39
|
up to date when create returns.
|
40
40
|
|
41
41
|
#### Notes on PostgreSQL
|
@@ -53,8 +53,8 @@ To switch databases using Apartment, use the following command:
|
|
53
53
|
|
54
54
|
Apartment::Database.switch('database_name')
|
55
55
|
|
56
|
-
When switch is called, all requests coming to ActiveRecord will be routed to the database
|
57
|
-
you specify (with the exception of excluded models, see below). To return to the 'root'
|
56
|
+
When switch is called, all requests coming to ActiveRecord will be routed to the database
|
57
|
+
you specify (with the exception of excluded models, see below). To return to the 'root'
|
58
58
|
database, call switch with no arguments.
|
59
59
|
|
60
60
|
### Switching Databases per request
|
@@ -67,32 +67,32 @@ to a database schema of the same name. It can be used like so:
|
|
67
67
|
# application.rb
|
68
68
|
module My Application
|
69
69
|
class Application < Rails::Application
|
70
|
-
|
70
|
+
|
71
71
|
config.middleware.use 'Apartment::Elevators::Subdomain'
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
## Config
|
76
76
|
|
77
77
|
The following config options should be set up in a Rails initializer such as:
|
78
78
|
|
79
79
|
config/initializers/apartment.rb
|
80
|
-
|
80
|
+
|
81
81
|
To set config options, add this to your initializer:
|
82
82
|
|
83
83
|
Apartment.configure do |config|
|
84
84
|
# set your options (described below) here
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
### Excluding models
|
88
88
|
|
89
89
|
If you have some models that should always access the 'root' database, you can specify this by configuring
|
90
90
|
Apartment using `Apartment.configure`. This will yield a config object for you. You can set excluded models like so:
|
91
|
-
|
91
|
+
|
92
92
|
config.excluded_models = ["User", "Company"] # these models will not be multi-tenanted, but remain in the global (public) namespace
|
93
93
|
|
94
94
|
Note that a string representation of the model name is now the standard so that models are properly constantized when reloaded in development
|
95
|
-
|
95
|
+
|
96
96
|
### Handling Environments
|
97
97
|
|
98
98
|
By default, when not using postgresql schemas, Apartment will prepend the environment to the database name
|
@@ -109,19 +109,31 @@ This object should yield an array of string representing each database name. Ex
|
|
109
109
|
|
110
110
|
# Dynamically get database names to migrate
|
111
111
|
config.database_names = lambda{ Customer.select(:database_name).map(&:database_name) }
|
112
|
-
|
112
|
+
|
113
113
|
# Use a static list of database names for migrate
|
114
114
|
config.database_names = ['db1', 'db2']
|
115
|
-
|
115
|
+
|
116
116
|
You can then migration your databases using the rake task:
|
117
|
-
|
117
|
+
|
118
118
|
rake apartment:migrate
|
119
|
-
|
119
|
+
|
120
120
|
This basically invokes `Apartment::Database.migrate(#{db_name})` for each database name supplied
|
121
121
|
from `Apartment.database_names`
|
122
122
|
|
123
123
|
### Delayed::Job
|
124
124
|
|
125
|
+
If using Rails ~> 3.2, you *must* use `delayed_job ~> 3.0`. It has better Rails 3 support plus has some major changes that affect the serialization of models.
|
126
|
+
I haven't been able to get `psych` working whatsoever as the YAML parser, so to get things to work properly, you must explicitly set the parser to `syck` *before* requiring `delayed_job`
|
127
|
+
This can be done in the `boot.rb` of your rails config *just above* where Bundler requires the gems from the Gemfile. It will look something like:
|
128
|
+
|
129
|
+
require 'rubygems'
|
130
|
+
require 'yaml'
|
131
|
+
YAML::ENGINE.yamler = 'syck'
|
132
|
+
|
133
|
+
# Set up gems listed in the Gemfile.
|
134
|
+
gemfile = File.expand_path('../../Gemfile', __FILE__)
|
135
|
+
...
|
136
|
+
|
125
137
|
In order to make ActiveRecord models play nice with DJ and Apartment, include `Apartment::Delayed::Requirements` in any model that is being serialized by DJ. Also ensure that the `database` attribute (provided by Apartment::Delayed::Requirements) is set on this model *before* it is serialized, to ensure that when it is fetched again, it is done so in the proper Apartment db context. For example:
|
126
138
|
|
127
139
|
class SomeModel < ActiveRecord::Base
|
@@ -129,12 +141,12 @@ In order to make ActiveRecord models play nice with DJ and Apartment, include `A
|
|
129
141
|
end
|
130
142
|
|
131
143
|
class SomeDJ
|
132
|
-
|
144
|
+
|
133
145
|
def initialize(model)
|
134
146
|
@model = model
|
135
147
|
@model.database = Apartment::Database.current_database
|
136
148
|
end
|
137
|
-
|
149
|
+
|
138
150
|
def perform
|
139
151
|
# do some stuff
|
140
152
|
end
|
data/apartment.gemspec
CHANGED
@@ -27,5 +27,6 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.add_development_dependency 'pg', '~> 0.11.0'
|
28
28
|
s.add_development_dependency 'mysql2', '~> 0.3.7'
|
29
29
|
s.add_development_dependency "silent-postgres", "~> 0.1.1"
|
30
|
-
s.add_development_dependency 'delayed_job', '~>
|
30
|
+
s.add_development_dependency 'delayed_job', '~> 3.0.1'
|
31
|
+
s.add_development_dependency 'delayed_job_active_record'
|
31
32
|
end
|
@@ -8,8 +8,8 @@ module ActiveRecord
|
|
8
8
|
Apartment::Database.process(val['database']) do
|
9
9
|
klass.find(val['attributes']['id'])
|
10
10
|
end
|
11
|
-
rescue ActiveRecord::RecordNotFound
|
12
|
-
raise Delayed::DeserializationError
|
11
|
+
rescue ActiveRecord::RecordNotFound => e
|
12
|
+
raise Delayed::DeserializationError, e.message
|
13
13
|
end
|
14
14
|
|
15
15
|
# Rails > 3.0 now uses encode_with to determine what to encode with yaml
|
@@ -12,11 +12,12 @@ module Apartment
|
|
12
12
|
attr_accessor :database
|
13
13
|
|
14
14
|
def before(job)
|
15
|
+
@_current_database = Apartment::Database.current_database
|
15
16
|
Apartment::Database.switch(job.payload_object.database) if job.payload_object.database
|
16
17
|
end
|
17
18
|
|
18
19
|
def after
|
19
|
-
Apartment::Database.
|
20
|
+
Apartment::Database.switch(@_current_database)
|
20
21
|
end
|
21
22
|
|
22
23
|
end
|
data/lib/apartment/version.rb
CHANGED
@@ -2,66 +2,66 @@ require 'spec_helper'
|
|
2
2
|
require 'apartment/adapters/postgresql_adapter' # specific adapters get dynamically loaded based on adapter name, so we must manually require here
|
3
3
|
|
4
4
|
describe Apartment::Adapters::PostgresqlAdapter do
|
5
|
-
|
5
|
+
|
6
6
|
before do
|
7
7
|
ActiveRecord::Base.establish_connection Apartment::Test.config['connections']['postgresql']
|
8
8
|
@schema_search_path = ActiveRecord::Base.connection.schema_search_path
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
after do
|
12
12
|
ActiveRecord::Base.clear_all_connections!
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
context "using schemas" do
|
16
|
-
|
16
|
+
|
17
17
|
let(:schema){ 'first_db_schema' }
|
18
18
|
let(:schema2){ 'another_db_schema' }
|
19
19
|
let(:database_names){ ActiveRecord::Base.connection.execute("SELECT nspname FROM pg_namespace;").collect{|row| row['nspname']} }
|
20
|
-
|
20
|
+
|
21
21
|
subject{ Apartment::Database.postgresql_adapter Apartment::Test.config['connections']['postgresql'].symbolize_keys }
|
22
|
-
|
22
|
+
|
23
23
|
before do
|
24
24
|
Apartment.use_postgres_schemas = true
|
25
25
|
subject.create(schema)
|
26
26
|
subject.create(schema2)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
after do
|
30
30
|
# sometimes we manually drop these schemas in testing, dont' care if we can't drop hence rescue
|
31
|
-
subject.drop(schema) rescue true
|
31
|
+
subject.drop(schema) rescue true
|
32
32
|
subject.drop(schema2) rescue true
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
describe "#create" do
|
36
|
-
|
36
|
+
|
37
37
|
it "should create the new schema" do
|
38
38
|
database_names.should include(schema)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
it "should load schema.rb to new schema" do
|
42
42
|
ActiveRecord::Base.connection.schema_search_path = schema
|
43
43
|
ActiveRecord::Base.connection.tables.should include('companies')
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
it "should reset connection when finished" do
|
47
47
|
ActiveRecord::Base.connection.schema_search_path.should_not == schema
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
it "should yield to block if passed" do
|
51
51
|
subject.drop(schema2) # so we don't get errors on creation
|
52
|
-
|
52
|
+
|
53
53
|
@count = 0 # set our variable so its visible in and outside of blocks
|
54
|
-
|
54
|
+
|
55
55
|
subject.create(schema2) do
|
56
56
|
@count = User.count
|
57
57
|
ActiveRecord::Base.connection.schema_search_path.should == schema2
|
58
58
|
User.create
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
subject.process(schema2){ User.count.should == @count + 1 }
|
62
62
|
end
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
describe "#drop" do
|
66
66
|
|
67
67
|
it "should delete the database" do
|
@@ -77,31 +77,31 @@ describe Apartment::Adapters::PostgresqlAdapter do
|
|
77
77
|
}.to raise_error(Apartment::SchemaNotFound)
|
78
78
|
end
|
79
79
|
end
|
80
|
-
|
81
|
-
|
80
|
+
|
81
|
+
|
82
82
|
describe "#process" do
|
83
83
|
it "should connect" do
|
84
84
|
subject.process(schema) do
|
85
85
|
ActiveRecord::Base.connection.schema_search_path.should == schema
|
86
86
|
end
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
it "should reset" do
|
90
90
|
subject.process(schema)
|
91
91
|
ActiveRecord::Base.connection.schema_search_path.should == @schema_search_path
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# We're often finding when using Apartment in tests, the `current_database` (ie the previously attached to schema)
|
95
95
|
# gets dropped, but process will try to return to that schema in a test. We should just reset if it doesnt exist
|
96
96
|
it "should not throw exception if current_database (schema) is no longer accessible" do
|
97
97
|
subject.switch(schema2)
|
98
|
-
|
98
|
+
|
99
99
|
expect {
|
100
100
|
subject.process(schema){ subject.drop(schema2) }
|
101
101
|
}.to_not raise_error(Apartment::SchemaNotFound)
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
describe "#reset" do
|
106
106
|
it "should reset connection" do
|
107
107
|
subject.switch(schema)
|
@@ -109,28 +109,28 @@ describe Apartment::Adapters::PostgresqlAdapter do
|
|
109
109
|
ActiveRecord::Base.connection.schema_search_path.should == @schema_search_path
|
110
110
|
end
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
describe "#switch" do
|
114
114
|
it "should connect to new schema" do
|
115
115
|
subject.switch(schema)
|
116
116
|
ActiveRecord::Base.connection.schema_search_path.should == schema
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
it "should reset connection if database is nil" do
|
120
120
|
subject.switch
|
121
121
|
ActiveRecord::Base.connection.schema_search_path.should == @schema_search_path
|
122
122
|
end
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
describe "#current_database" do
|
126
126
|
it "should return the current schema name" do
|
127
127
|
subject.switch(schema)
|
128
128
|
subject.current_database.should == schema
|
129
129
|
end
|
130
130
|
end
|
131
|
-
|
131
|
+
|
132
132
|
end
|
133
|
-
|
133
|
+
|
134
134
|
context "using databases" do
|
135
135
|
# TODO
|
136
136
|
end
|
data/spec/dummy/config/boot.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'delayed_job'
|
3
|
-
|
3
|
+
require 'delayed_job_active_record'
|
4
4
|
|
5
5
|
describe Apartment::Delayed do
|
6
6
|
|
@@ -72,4 +72,17 @@ describe Apartment::Delayed do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
describe Apartment::Delayed::Job::Hooks do
|
76
|
+
|
77
|
+
let(:worker){ Delayed::Worker.new }
|
78
|
+
let(:job){ Delayed::Job.enqueue User.new }
|
79
|
+
|
80
|
+
it "should switch to previous db" do
|
81
|
+
Apartment::Database.switch database
|
82
|
+
worker.run(job)
|
83
|
+
|
84
|
+
Apartment::Database.current_database.should == database
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
75
88
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apartment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-03-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &2156199960 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.1.2
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2156199960
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rake
|
28
|
-
requirement: &
|
28
|
+
requirement: &2156198740 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 0.9.2
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2156198740
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: sqlite3
|
39
|
-
requirement: &
|
39
|
+
requirement: &2156197960 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *2156197960
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rspec
|
50
|
-
requirement: &
|
50
|
+
requirement: &2156197060 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ~>
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: 2.8.0
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *2156197060
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: rspec-rails
|
61
|
-
requirement: &
|
61
|
+
requirement: &2156196160 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ~>
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: 2.8.0
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *2156196160
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: capybara
|
72
|
-
requirement: &
|
72
|
+
requirement: &2156195360 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - =
|
@@ -77,10 +77,10 @@ dependencies:
|
|
77
77
|
version: 1.0.0
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *2156195360
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: pg
|
83
|
-
requirement: &
|
83
|
+
requirement: &2156194560 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
85
85
|
requirements:
|
86
86
|
- - ~>
|
@@ -88,10 +88,10 @@ dependencies:
|
|
88
88
|
version: 0.11.0
|
89
89
|
type: :development
|
90
90
|
prerelease: false
|
91
|
-
version_requirements: *
|
91
|
+
version_requirements: *2156194560
|
92
92
|
- !ruby/object:Gem::Dependency
|
93
93
|
name: mysql2
|
94
|
-
requirement: &
|
94
|
+
requirement: &2156176740 !ruby/object:Gem::Requirement
|
95
95
|
none: false
|
96
96
|
requirements:
|
97
97
|
- - ~>
|
@@ -99,10 +99,10 @@ dependencies:
|
|
99
99
|
version: 0.3.7
|
100
100
|
type: :development
|
101
101
|
prerelease: false
|
102
|
-
version_requirements: *
|
102
|
+
version_requirements: *2156176740
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: silent-postgres
|
105
|
-
requirement: &
|
105
|
+
requirement: &2156175840 !ruby/object:Gem::Requirement
|
106
106
|
none: false
|
107
107
|
requirements:
|
108
108
|
- - ~>
|
@@ -110,18 +110,29 @@ dependencies:
|
|
110
110
|
version: 0.1.1
|
111
111
|
type: :development
|
112
112
|
prerelease: false
|
113
|
-
version_requirements: *
|
113
|
+
version_requirements: *2156175840
|
114
114
|
- !ruby/object:Gem::Dependency
|
115
115
|
name: delayed_job
|
116
|
-
requirement: &
|
116
|
+
requirement: &2156174740 !ruby/object:Gem::Requirement
|
117
117
|
none: false
|
118
118
|
requirements:
|
119
119
|
- - ~>
|
120
120
|
- !ruby/object:Gem::Version
|
121
|
-
version:
|
121
|
+
version: 3.0.1
|
122
122
|
type: :development
|
123
123
|
prerelease: false
|
124
|
-
version_requirements: *
|
124
|
+
version_requirements: *2156174740
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: delayed_job_active_record
|
127
|
+
requirement: &2156173700 !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ! '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: *2156173700
|
125
136
|
description: Apartment allows Rails applications to deal with database multitenancy
|
126
137
|
email:
|
127
138
|
- ryan@ryanbrunner.com
|
@@ -221,7 +232,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
221
232
|
version: '0'
|
222
233
|
segments:
|
223
234
|
- 0
|
224
|
-
hash:
|
235
|
+
hash: -3479851057211563611
|
225
236
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
237
|
none: false
|
227
238
|
requirements:
|
@@ -230,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
230
241
|
version: '0'
|
231
242
|
segments:
|
232
243
|
- 0
|
233
|
-
hash:
|
244
|
+
hash: -3479851057211563611
|
234
245
|
requirements: []
|
235
246
|
rubyforge_project:
|
236
247
|
rubygems_version: 1.8.10
|