apartment 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +45 -4
- data/Appraisals +12 -9
- data/HISTORY.md +18 -0
- data/README.md +69 -42
- data/Rakefile +24 -5
- data/apartment.gemspec +6 -16
- data/docker-compose.yml +14 -0
- data/gemfiles/rails_4_0.gemfile +1 -1
- data/gemfiles/rails_4_1.gemfile +1 -1
- data/gemfiles/rails_4_2.gemfile +1 -1
- data/gemfiles/rails_5_0.gemfile +1 -1
- data/gemfiles/{rails_3_2.gemfile → rails_5_1.gemfile} +2 -3
- data/gemfiles/rails_master.gemfile +12 -0
- data/lib/apartment.rb +3 -25
- data/lib/apartment/adapters/abstract_adapter.rb +19 -44
- data/lib/apartment/adapters/postgresql_adapter.rb +17 -3
- data/lib/apartment/elevators/generic.rb +1 -20
- data/lib/apartment/elevators/subdomain.rb +15 -4
- data/lib/apartment/railtie.rb +5 -2
- data/lib/apartment/tenant.rb +0 -10
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +13 -8
- data/lib/tasks/apartment.rake +2 -2
- data/spec/adapters/mysql2_adapter_spec.rb +8 -0
- data/spec/apartment_spec.rb +1 -5
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/database.yml.sample +3 -1
- data/spec/dummy/db/migrate/20110613152810_create_dummy_models.rb +2 -1
- data/spec/dummy/db/migrate/20111202022214_create_table_books.rb +2 -1
- data/spec/dummy_engine/config/initializers/apartment.rb +3 -3
- data/spec/examples/connection_adapter_examples.rb +8 -0
- data/spec/examples/generic_adapter_examples.rb +35 -17
- data/spec/examples/schema_adapter_examples.rb +8 -0
- data/spec/integration/query_caching_spec.rb +63 -23
- data/spec/spec_helper.rb +12 -0
- data/spec/tenant_spec.rb +10 -3
- data/spec/unit/config_spec.rb +0 -7
- data/spec/unit/elevators/subdomain_spec.rb +28 -8
- metadata +20 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b431585840ff2cba38b0280bc2a4ee7e6460a089
|
4
|
+
data.tar.gz: 3f7679220b8adcf6ad0f832c70d5d2ea82ccc3c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f41b445022a6ec41ba6a34f2cbc3d5a086be9495972f8e5af8ab557168a9e649c74d76299a5043739cd2048f2a625701eeb47ea702a70857b6c18bab54a7648
|
7
|
+
data.tar.gz: cf3fd76a826a36b3a7b0b4a51bf5d68dc34624a830ddc8a2e13d9e7a2f88cd03e5541c0d53863bccffb14f97cd81c5bdd131943cf5b1918495cc86a83a527e44
|
data/.travis.yml
CHANGED
@@ -4,20 +4,61 @@ rvm:
|
|
4
4
|
- 2.1.9
|
5
5
|
- 2.2.4
|
6
6
|
- 2.3.1
|
7
|
+
- 2.4.1
|
8
|
+
- ruby-head
|
7
9
|
- jruby-9.0.5.0
|
10
|
+
- jruby-9.1.9.0
|
8
11
|
gemfile:
|
9
|
-
- gemfiles/rails_3_2.gemfile
|
10
12
|
- gemfiles/rails_4_0.gemfile
|
11
13
|
- gemfiles/rails_4_1.gemfile
|
12
14
|
- gemfiles/rails_4_2.gemfile
|
15
|
+
- gemfiles/rails_5_0.gemfile
|
16
|
+
- gemfiles/rails_5_1.gemfile
|
17
|
+
- gemfiles/rails_master.gemfile
|
13
18
|
bundler_args: --without local
|
14
19
|
before_install:
|
15
20
|
- gem install bundler -v '> 1.5.0'
|
16
21
|
env:
|
17
22
|
RUBY_GC_MALLOC_LIMIT: 90000000
|
18
|
-
|
23
|
+
RUBY_GC_HEAP_FREE_SLOTS: 200000
|
19
24
|
matrix:
|
25
|
+
allow_failures:
|
26
|
+
- rvm: ruby-head
|
27
|
+
- gemfile: gemfiles/rails_master.gemfile
|
20
28
|
exclude:
|
21
|
-
- rvm: 2.
|
22
|
-
gemfile: gemfiles/
|
29
|
+
- rvm: 2.0.0
|
30
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
31
|
+
- rvm: 2.0.0
|
32
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
33
|
+
- rvm: 2.0.0
|
34
|
+
gemfile: gemfiles/rails_master.gemfile
|
35
|
+
- rvm: 2.1.9
|
36
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
37
|
+
- rvm: 2.1.9
|
38
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
39
|
+
- rvm: 2.1.9
|
40
|
+
gemfile: gemfiles/rails_master.gemfile
|
41
|
+
- rvm: 2.4.1
|
42
|
+
gemfile: gemfiles/rails_4_0.gemfile
|
43
|
+
- rvm: 2.4.1
|
44
|
+
gemfile: gemfiles/rails_4_1.gemfile
|
45
|
+
- rvm: ruby-head
|
46
|
+
gemfile: gemfiles/rails_4_0.gemfile
|
47
|
+
- rvm: ruby-head
|
48
|
+
gemfile: gemfiles/rails_4_1.gemfile
|
49
|
+
- rvm: jruby-9.0.5.0
|
50
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
51
|
+
- rvm: jruby-9.0.5.0
|
52
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
53
|
+
- rvm: jruby-9.0.5.0
|
54
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
55
|
+
- rvm: jruby-9.0.5.0
|
56
|
+
gemfile: gemfiles/rails_master.gemfile
|
57
|
+
- rvm: jruby-9.1.9.0
|
58
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
59
|
+
- rvm: jruby-9.1.9.0
|
60
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
61
|
+
- rvm: jruby-9.1.9.0
|
62
|
+
gemfile: gemfiles/rails_master.gemfile
|
23
63
|
fast_finish: true
|
64
|
+
cache: bundler
|
data/Appraisals
CHANGED
@@ -1,20 +1,23 @@
|
|
1
|
-
appraise "rails-3-2" do
|
2
|
-
gem "rails", "~> 3.2"
|
3
|
-
gem "test-unit", "~> 3.0"
|
4
|
-
end
|
5
|
-
|
6
1
|
appraise "rails-4-0" do
|
7
|
-
gem "rails", "~> 4.0"
|
2
|
+
gem "rails", "~> 4.0.0"
|
8
3
|
end
|
9
4
|
|
10
5
|
appraise "rails-4-1" do
|
11
|
-
gem "rails", "~> 4.1"
|
6
|
+
gem "rails", "~> 4.1.0"
|
12
7
|
end
|
13
8
|
|
14
9
|
appraise "rails-4-2" do
|
15
|
-
gem "rails", "~> 4.2"
|
10
|
+
gem "rails", "~> 4.2.0"
|
16
11
|
end
|
17
12
|
|
18
13
|
appraise "rails-5-0" do
|
19
|
-
gem "rails", "~> 5.0"
|
14
|
+
gem "rails", "~> 5.0.0"
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise "rails-5-1" do
|
18
|
+
gem "rails", "5.1.1"
|
19
|
+
end
|
20
|
+
|
21
|
+
appraise "rails-master" do
|
22
|
+
gem "rails", git: 'https://github.com/rails/rails.git'
|
20
23
|
end
|
data/HISTORY.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# 2.0.0
|
2
|
+
* July 26, 2017
|
3
|
+
|
4
|
+
- Raise FileNotFound rather than abort when loading files [meganemura]
|
5
|
+
- Add 5.1 support with fixes for deprecations [meganemura]
|
6
|
+
- Fix tests for 5.x and a host of dev-friendly improvements [meganemura]
|
7
|
+
- Keep query cache config after switching databases [fernandomm]
|
8
|
+
- Pass constants not strings to middleware stack (Rails 5) [tzabaman]
|
9
|
+
- Remove deprecations from 1.0.0 [caironoleto]
|
10
|
+
- Replace `tld_length` configuration option with PublicSuffix gem for the
|
11
|
+
subdomain elevator [humancopy]
|
12
|
+
- Pass full config to create_database to allow :encoding/:collation/etc
|
13
|
+
[kakipo]
|
14
|
+
- Don't retain a connection during initialization [mikecmpbll]
|
15
|
+
- Fix database name escaping in drop_command [mikecmpbll]
|
16
|
+
- Skip initialization for assets:clean and assets:precompile tasks
|
17
|
+
[frank-west-iii]
|
18
|
+
|
1
19
|
# 1.2.0
|
2
20
|
* July 28, 2016
|
3
21
|
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Apartment
|
2
|
-
|
3
|
-
[![
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/apartment.svg)](https://badge.fury.io/rb/apartment)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/influitive/apartment/badges/gpa.svg)](https://codeclimate.com/github/influitive/apartment)
|
5
|
+
[![Build Status](https://travis-ci.org/influitive/apartment.svg?branch=development)](https://travis-ci.org/influitive/apartment)
|
4
6
|
|
5
7
|
*Multitenancy for Rails and ActiveRecord*
|
6
8
|
|
@@ -29,7 +31,6 @@ this poll, we'd greatly appreciated it.
|
|
29
31
|
gem 'rails', '4.2.1', github: 'influitive/rails', tag: 'v4.2.1.memfix'
|
30
32
|
```
|
31
33
|
|
32
|
-
|
33
34
|
## Installation
|
34
35
|
|
35
36
|
### Rails
|
@@ -57,7 +58,9 @@ on a per-user basis, look under "Usage - Switching tenants per request", below.
|
|
57
58
|
> * for Rails 3.1.x: _Rails ~> 3.1.2_, it contains a [patch](https://github.com/rails/rails/pull/3232) that makes prepared statements work with multiple schemas
|
58
59
|
|
59
60
|
## Usage
|
61
|
+
|
60
62
|
### Video Tutorial
|
63
|
+
|
61
64
|
How to separate your application data into different accounts or companies.
|
62
65
|
[GoRails #47](https://gorails.com/episodes/multitenancy-with-apartment)
|
63
66
|
|
@@ -103,6 +106,9 @@ tenant, call switch with no arguments.
|
|
103
106
|
You can have Apartment route to the appropriate tenant by adding some Rack middleware.
|
104
107
|
Apartment can support many different "Elevators" that can take care of this routing to your data.
|
105
108
|
|
109
|
+
**NOTE: when switching tenants per-request, keep in mind that the order of your Rack middleware is important.**
|
110
|
+
See the [Middleware Considerations](#middleware-considerations) section for more.
|
111
|
+
|
106
112
|
The initializer above will generate the appropriate code for the Subdomain elevator
|
107
113
|
by default. You can see this in `config/initializers/apartment.rb` after running
|
108
114
|
that generator. If you're *not* using the generator, you can specify your
|
@@ -114,27 +120,19 @@ manually in your `application.rb` like so
|
|
114
120
|
require 'apartment/elevators/subdomain' # or 'domain' or 'generic'
|
115
121
|
```
|
116
122
|
|
117
|
-
|
123
|
+
#### Switch on subdomain
|
124
|
+
|
118
125
|
In house, we use the subdomain elevator, which analyzes the subdomain of the request and switches to a tenant schema of the same name. It can be used like so:
|
119
126
|
|
120
127
|
```ruby
|
121
128
|
# application.rb
|
122
129
|
module MyApplication
|
123
130
|
class Application < Rails::Application
|
124
|
-
config.middleware.use
|
131
|
+
config.middleware.use Apartment::Elevators::Subdomain
|
125
132
|
end
|
126
133
|
end
|
127
134
|
```
|
128
135
|
|
129
|
-
By default, the subdomain elevator assumes that the parent domain consists of two segments, e.g. 'example.com'. If this isn't the case, you can adjust the `tld_length` (top level domain length) configuration variable, which defaults to 1. For example, if you are using 'localhost' in development:
|
130
|
-
```ruby
|
131
|
-
# config/initializers/apartment.rb
|
132
|
-
Apartment.configure do |config|
|
133
|
-
...
|
134
|
-
config.tld_length = 0 if Rails.env == 'development'
|
135
|
-
end
|
136
|
-
```
|
137
|
-
|
138
136
|
If you want to exclude a domain, for example if you don't want your application to treat www like a subdomain, in an initializer in your application, you can set the following:
|
139
137
|
|
140
138
|
```ruby
|
@@ -144,14 +142,15 @@ Apartment::Elevators::Subdomain.excluded_subdomains = ['www']
|
|
144
142
|
|
145
143
|
This functions much in the same way as Apartment.excluded_models. This example will prevent switching your tenant when the subdomain is www. Handy for subdomains like: "public", "www", and "admin" :)
|
146
144
|
|
147
|
-
|
148
|
-
|
145
|
+
#### Switch on first subdomain
|
146
|
+
|
147
|
+
To switch on the first subdomain, which analyzes the chain of subdomains of the request and switches to a tenant schema of the first name in the chain (e.g. owls.birds.animals.com would switch to "owl"). It can be used like so:
|
149
148
|
|
150
149
|
```ruby
|
151
150
|
# application.rb
|
152
151
|
module MyApplication
|
153
152
|
class Application < Rails::Application
|
154
|
-
config.middleware.use
|
153
|
+
config.middleware.use Apartment::Elevators::FirstSubdomain
|
155
154
|
end
|
156
155
|
end
|
157
156
|
```
|
@@ -163,41 +162,44 @@ If you want to exclude a domain, for example if you don't want your application
|
|
163
162
|
Apartment::Elevators::FirstSubdomain.excluded_subdomains = ['www']
|
164
163
|
```
|
165
164
|
|
166
|
-
This functions much in the same way as the Subdomain elevator.
|
165
|
+
This functions much in the same way as the Subdomain elevator. **NOTE:** in fact, at the time of this writing, the `Subdomain` and `FirstSubdomain` elevators both use the first subdomain ([#339](https://github.com/influitive/apartment/issues/339#issuecomment-235578610)). If you need to switch on larger parts of a Subdomain, consider using a Custom Elevator.
|
166
|
+
|
167
|
+
#### Switch on domain
|
167
168
|
|
168
|
-
**Switch on domain**
|
169
169
|
To switch based on full domain (excluding subdomains *ie 'www'* and top level domains *ie '.com'* ) use the following:
|
170
170
|
|
171
171
|
```ruby
|
172
172
|
# application.rb
|
173
173
|
module MyApplication
|
174
174
|
class Application < Rails::Application
|
175
|
-
config.middleware.use
|
175
|
+
config.middleware.use Apartment::Elevators::Domain
|
176
176
|
end
|
177
177
|
end
|
178
178
|
```
|
179
179
|
|
180
|
-
|
180
|
+
#### Switch on full host using a hash
|
181
|
+
|
181
182
|
To switch based on full host with a hash to find corresponding tenant name use the following:
|
182
183
|
|
183
184
|
```ruby
|
184
185
|
# application.rb
|
185
186
|
module MyApplication
|
186
187
|
class Application < Rails::Application
|
187
|
-
config.middleware.use
|
188
|
+
config.middleware.use Apartment::Elevators::HostHash, {'example.com' => 'example_tenant'}
|
188
189
|
end
|
189
190
|
end
|
190
191
|
```
|
191
192
|
|
192
|
-
|
193
|
-
|
193
|
+
#### Custom Elevator
|
194
|
+
|
195
|
+
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 tenant. Use like so:
|
194
196
|
|
195
197
|
```ruby
|
196
198
|
# application.rb
|
197
199
|
module MyApplication
|
198
200
|
class Application < Rails::Application
|
199
201
|
# Obviously not a contrived example
|
200
|
-
config.middleware.use
|
202
|
+
config.middleware.use Apartment::Elevators::Generic, Proc.new { |request| request.host.reverse }
|
201
203
|
end
|
202
204
|
end
|
203
205
|
```
|
@@ -225,6 +227,28 @@ class MyCustomElevator < Apartment::Elevators::Generic
|
|
225
227
|
end
|
226
228
|
```
|
227
229
|
|
230
|
+
#### Middleware Considerations
|
231
|
+
|
232
|
+
In the examples above, we show the Apartment middleware being appended to the Rack stack with
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
Rails.application.config.middleware.use Apartment::Elevators::Subdomain
|
236
|
+
```
|
237
|
+
|
238
|
+
By default, the Subdomain middleware switches into a Tenant based on the subdomain at the beginning of the request, and when the request is finished, it switches back to the "public" Tenant. This happens in the [Generic](https://github.com/influitive/apartment/blob/development/lib/apartment/elevators/generic.rb#L22) elevator, so all elevators that inherit from this elevator will operate as such.
|
239
|
+
|
240
|
+
It's also good to note that Apartment switches back to the "public" tenant any time an error is raised in your application.
|
241
|
+
|
242
|
+
This works okay for simple applications, but it's important to consider that you may want to maintain the "selected" tenant through different parts of the Rack application stack. For example, the [Devise](https://github.com/plataformatec/devise) gem adds the `Warden::Manager` middleware at the end of the stack in the examples above, our `Apartment::Elevators::Subdomain` middleware would come after it. Trouble is, Apartment resets the selected tenant after the request is finish, so some redirects (e.g. authentication) in Devise will be run in the context of the "public" tenant. The same issue would also effect a gem such as the [better_errors](https://github.com/charliesome/better_errors) gem which inserts a middleware quite early in the Rails middleware stack.
|
243
|
+
|
244
|
+
To resolve this issue, consider adding the Apartment middleware at a location in the Rack stack that makes sense for your needs, e.g.:
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
Rails.application.config.middleware.insert_before 'Warden::Manager', 'Apartment::Elevators::Subdomain'
|
248
|
+
```
|
249
|
+
|
250
|
+
Now work done in the Warden middleware is wrapped in the `Apartment::Tenant.switch` context started in the Generic elevator.
|
251
|
+
|
228
252
|
### Dropping Tenants
|
229
253
|
|
230
254
|
To drop tenants using Apartment, use the following command:
|
@@ -251,7 +275,7 @@ end
|
|
251
275
|
|
252
276
|
### Excluding models
|
253
277
|
|
254
|
-
If you have some models that should always access the 'public' tenant, you can specify this by configuring Apartment using `Apartment.configure`.
|
278
|
+
If you have some models that should always access the 'public' tenant, you can specify this by configuring Apartment using `Apartment.configure`. This will yield a config object for you. You can set excluded models like so:
|
255
279
|
|
256
280
|
```ruby
|
257
281
|
config.excluded_models = ["User", "Company"] # these models will not be multi-tenanted, but remain in the global (public) namespace
|
@@ -259,7 +283,7 @@ config.excluded_models = ["User", "Company"] # these models will not be m
|
|
259
283
|
|
260
284
|
Note that a string representation of the model name is now the standard so that models are properly constantized when reloaded in development
|
261
285
|
|
262
|
-
Rails will always access the 'public' tenant when accessing these models,
|
286
|
+
Rails will always access the 'public' tenant when accessing these models, but note that tables will be created in all schemas. This may not be ideal, but its done this way because otherwise rails wouldn't be able to properly generate the schema.rb file.
|
263
287
|
|
264
288
|
> **NOTE - Many-To-Many Excluded Models:**
|
265
289
|
> Since model exclusions must come from referencing a real ActiveRecord model, `has_and_belongs_to_many` is NOT supported. In order to achieve a many-to-many relationship for excluded models, you MUST use `has_many :through`. This way you can reference the join model in the excluded models configuration.
|
@@ -267,6 +291,7 @@ Rails will always access the 'public' tenant when accessing these models, but n
|
|
267
291
|
### Postgresql Schemas
|
268
292
|
|
269
293
|
## Providing a Different default_schema
|
294
|
+
|
270
295
|
By default, ActiveRecord will use `"$user", public` as the default `schema_search_path`. This can be modified if you wish to use a different default schema be setting:
|
271
296
|
|
272
297
|
```ruby
|
@@ -276,14 +301,16 @@ config.default_schema = "some_other_schema"
|
|
276
301
|
With that set, all excluded models will use this schema as the table name prefix instead of `public` and `reset` on `Apartment::Tenant` will return to this schema as well.
|
277
302
|
|
278
303
|
## Persistent Schemas
|
279
|
-
|
304
|
+
|
305
|
+
Apartment will normally just switch the `schema_search_path` whole hog to the one passed in. This can lead to problems if you want other schemas to always be searched as well. Enter `persistent_schemas`. You can configure a list of other schemas that will always remain in the search path, while the default gets swapped out:
|
280
306
|
|
281
307
|
```ruby
|
282
308
|
config.persistent_schemas = ['some', 'other', 'schemas']
|
283
309
|
```
|
284
310
|
|
285
311
|
### Installing Extensions into Persistent Schemas
|
286
|
-
|
312
|
+
|
313
|
+
Persistent Schemas have numerous useful applications. [Hstore](http://www.postgresql.org/docs/9.1/static/hstore.html), for instance, is a popular storage engine for Postgresql. In order to use extensions such as Hstore, you have to install it to a specific schema and have that always in the `schema_search_path`.
|
287
314
|
|
288
315
|
When using extensions, keep in mind:
|
289
316
|
* Extensions can only be installed into one schema per database, so we will want to install it into a schema that is always available in the `schema_search_path`
|
@@ -306,7 +333,6 @@ When using extensions, keep in mind:
|
|
306
333
|
# BEFORE db:migrate. #
|
307
334
|
##################################################
|
308
335
|
|
309
|
-
|
310
336
|
namespace :db do
|
311
337
|
desc 'Also create shared_extensions Schema'
|
312
338
|
task :extensions => :environment do
|
@@ -330,7 +356,7 @@ end
|
|
330
356
|
|
331
357
|
#### 2. Ensure the schema is in Rails' default connection
|
332
358
|
|
333
|
-
Next, your `database.yml` file must mimic what you've set for your default and persistent schemas in Apartment.
|
359
|
+
Next, your `database.yml` file must mimic what you've set for your default and persistent schemas in Apartment. When you run migrations with Rails, it won't know about the extensions schema because Apartment isn't injected into the default connection, it's done on a per-request basis, therefore Rails doesn't know about `hstore` or `uuid-ossp` during migrations. To do so, add the following to your `database.yml` for all environments
|
334
360
|
|
335
361
|
```yaml
|
336
362
|
# database.yml
|
@@ -351,6 +377,7 @@ This would be for a config with `default_schema` set to `public` and `persistent
|
|
351
377
|
To double check, login to the console of your Heroku app and see if `Apartment.connection.schema_search_path` is `public,hstore`
|
352
378
|
|
353
379
|
#### 3. Ensure the schema is in the apartment config
|
380
|
+
|
354
381
|
```ruby
|
355
382
|
# config/initializers/apartment.rb
|
356
383
|
...
|
@@ -359,6 +386,7 @@ config.persistent_schemas = ['shared_extensions']
|
|
359
386
|
```
|
360
387
|
|
361
388
|
#### Alternative: Creating schema by default
|
389
|
+
|
362
390
|
Another way that we've successfully configured hstore for our applications is to add it into the
|
363
391
|
postgresql template1 database so that every tenant that gets created has it by default.
|
364
392
|
|
@@ -377,7 +405,8 @@ also contain the tenanted tables, which is an open issue with no real milestone
|
|
377
405
|
Happy to accept PR's on the matter.
|
378
406
|
|
379
407
|
#### Alternative: Creating new schemas by using raw SQL dumps
|
380
|
-
|
408
|
+
|
409
|
+
Apartment can be forced to use raw SQL dumps insted of `schema.rb` for creating new schemas. Use this when you are using some extra features in postgres that can't be represented in `schema.rb`, like materialized views etc.
|
381
410
|
|
382
411
|
This only applies while using postgres adapter and `config.use_schemas` is set to `true`.
|
383
412
|
(Note: this option doesn't use `db/structure.sql`, it creates SQL dump by executing `pg_dump`)
|
@@ -387,12 +416,11 @@ Enable this option with:
|
|
387
416
|
config.use_sql = true
|
388
417
|
```
|
389
418
|
|
390
|
-
|
391
419
|
### Managing Migrations
|
392
420
|
|
393
421
|
In order to migrate all of your tenants (or postgresql schemas) you need to provide a list
|
394
|
-
of dbs to Apartment.
|
395
|
-
This object should yield an array of string representing each tenant name.
|
422
|
+
of dbs to Apartment. You can make this dynamic by providing a Proc object to be called on migrations.
|
423
|
+
This object should yield an array of string representing each tenant name. Example:
|
396
424
|
|
397
425
|
```ruby
|
398
426
|
# Dynamically get tenant names to migrate
|
@@ -418,8 +446,8 @@ Note that you can disable the default migrating of all tenants with `db:migrate`
|
|
418
446
|
### Handling Environments
|
419
447
|
|
420
448
|
By default, when not using postgresql schemas, Apartment will prepend the environment to the tenant name
|
421
|
-
to ensure there is no conflict between your environments.
|
422
|
-
and test environments.
|
449
|
+
to ensure there is no conflict between your environments. This is mainly for the benefit of your development
|
450
|
+
and test environments. If you wish to turn this option off in production, you could do something like:
|
423
451
|
|
424
452
|
```ruby
|
425
453
|
config.prepend_environment = !Rails.env.production?
|
@@ -454,7 +482,8 @@ end
|
|
454
482
|
```
|
455
483
|
|
456
484
|
## Delayed::Job
|
457
|
-
|
485
|
+
|
486
|
+
Has been removed. See [apartment-sidekiq](https://github.com/influitive/apartment-sidekiq) for a better backgrounding experience.
|
458
487
|
|
459
488
|
## Contributing
|
460
489
|
|
@@ -462,13 +491,11 @@ end
|
|
462
491
|
* Copy them into the same directory but with the name `database.yml`
|
463
492
|
* Edit them to fit your own settings
|
464
493
|
* Rake tasks (see the Rakefile) will help you setup your dbs necessary to run tests
|
465
|
-
* Please issue pull requests to the `development` branch.
|
466
|
-
* Ensure that your code is accompanied with tests.
|
494
|
+
* Please issue pull requests to the `development` branch. All development happens here, master is used for releases.
|
495
|
+
* Ensure that your code is accompanied with tests. No code will be merged without tests
|
467
496
|
|
468
497
|
* If you're looking to help, check out the TODO file for some upcoming changes I'd like to implement in Apartment.
|
469
498
|
|
470
499
|
## License
|
471
500
|
|
472
501
|
Apartment is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
473
|
-
|
474
|
-
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/influitive/apartment/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ require "rspec/core/rake_task"
|
|
9
9
|
|
10
10
|
RSpec::Core::RakeTask.new(:spec => %w{ db:copy_credentials db:test:prepare }) do |spec|
|
11
11
|
spec.pattern = "spec/**/*_spec.rb"
|
12
|
-
# spec.rspec_opts = '--order rand:
|
12
|
+
# spec.rspec_opts = '--order rand:47078'
|
13
13
|
end
|
14
14
|
|
15
15
|
namespace :spec do
|
@@ -51,7 +51,13 @@ namespace :postgres do
|
|
51
51
|
|
52
52
|
desc 'Build the PostgreSQL test databases'
|
53
53
|
task :build_db do
|
54
|
-
|
54
|
+
params = []
|
55
|
+
params << "-E UTF8"
|
56
|
+
params << pg_config['database']
|
57
|
+
params << "-U#{pg_config['username']}"
|
58
|
+
params << "-h#{pg_config['host']}" if pg_config['host']
|
59
|
+
params << "-p#{pg_config['port']}" if pg_config['port']
|
60
|
+
%x{ createdb #{params.join(' ')} } rescue "test db already exists"
|
55
61
|
ActiveRecord::Base.establish_connection pg_config
|
56
62
|
ActiveRecord::Migrator.migrate('spec/dummy/db/migrate')
|
57
63
|
end
|
@@ -59,7 +65,12 @@ namespace :postgres do
|
|
59
65
|
desc "drop the PostgreSQL test database"
|
60
66
|
task :drop_db do
|
61
67
|
puts "dropping database #{pg_config['database']}"
|
62
|
-
|
68
|
+
params = []
|
69
|
+
params << pg_config['database']
|
70
|
+
params << "-U#{pg_config['username']}"
|
71
|
+
params << "-h#{pg_config['host']}" if pg_config['host']
|
72
|
+
params << "-p#{pg_config['port']}" if pg_config['port']
|
73
|
+
%x{ dropdb #{params.join(' ')} }
|
63
74
|
end
|
64
75
|
|
65
76
|
end
|
@@ -70,7 +81,11 @@ namespace :mysql do
|
|
70
81
|
|
71
82
|
desc 'Build the MySQL test databases'
|
72
83
|
task :build_db do
|
73
|
-
|
84
|
+
params = []
|
85
|
+
params << "-h #{my_config['host']}" if my_config['host']
|
86
|
+
params << "-u #{my_config['username']}" if my_config['username']
|
87
|
+
params << "-p#{my_config['password']}" if my_config['password']
|
88
|
+
%x{ mysqladmin #{params.join(' ')} create #{my_config['database']} } rescue "test db already exists"
|
74
89
|
ActiveRecord::Base.establish_connection my_config
|
75
90
|
ActiveRecord::Migrator.migrate('spec/dummy/db/migrate')
|
76
91
|
end
|
@@ -78,7 +93,11 @@ namespace :mysql do
|
|
78
93
|
desc "drop the MySQL test database"
|
79
94
|
task :drop_db do
|
80
95
|
puts "dropping database #{my_config['database']}"
|
81
|
-
|
96
|
+
params = []
|
97
|
+
params << "-h #{my_config['host']}" if my_config['host']
|
98
|
+
params << "-u #{my_config['username']}" if my_config['username']
|
99
|
+
params << "-p#{my_config['password']}" if my_config['password']
|
100
|
+
%x{ mysqladmin #{params.join(' ')} drop #{my_config['database']} --force}
|
82
101
|
end
|
83
102
|
|
84
103
|
end
|