apartment 0.26.1 → 1.0.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 +4 -4
- data/.rspec +1 -1
- data/.ruby-version +1 -1
- data/.travis.yml +9 -0
- data/HISTORY.md +8 -0
- data/README.md +30 -7
- data/TODO.md +9 -0
- data/apartment.gemspec +9 -8
- data/lib/apartment.rb +9 -18
- data/lib/apartment/adapters/abstract_adapter.rb +63 -30
- data/lib/apartment/adapters/jdbc_mysql_adapter.rb +2 -2
- data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +3 -3
- data/lib/apartment/adapters/mysql2_adapter.rb +10 -6
- data/lib/apartment/adapters/postgresql_adapter.rb +15 -21
- data/lib/apartment/adapters/sqlite3_adapter.rb +4 -4
- data/lib/apartment/deprecation.rb +13 -0
- data/lib/apartment/elevators/generic.rb +3 -2
- data/lib/apartment/elevators/host_hash.rb +1 -1
- data/lib/apartment/migrator.rb +3 -3
- data/lib/apartment/tasks/enhancements.rb +31 -21
- data/lib/apartment/tenant.rb +10 -7
- data/lib/apartment/version.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +41 -22
- data/lib/tasks/apartment.rake +1 -1
- data/spec/adapters/jdbc_mysql_adapter_spec.rb +1 -1
- data/spec/adapters/jdbc_postgresql_adapter_spec.rb +2 -2
- data/spec/adapters/mysql2_adapter_spec.rb +4 -2
- data/spec/adapters/postgresql_adapter_spec.rb +3 -3
- data/spec/adapters/sqlite3_adapter_spec.rb +1 -1
- data/spec/dummy_engine/.gitignore +8 -0
- data/spec/dummy_engine/Gemfile +15 -0
- data/spec/dummy_engine/Rakefile +34 -0
- data/spec/dummy_engine/bin/rails +12 -0
- data/spec/dummy_engine/config/initializers/apartment.rb +51 -0
- data/spec/dummy_engine/dummy_engine.gemspec +24 -0
- data/spec/dummy_engine/lib/dummy_engine.rb +4 -0
- data/spec/dummy_engine/lib/dummy_engine/engine.rb +4 -0
- data/spec/dummy_engine/lib/dummy_engine/version.rb +3 -0
- data/spec/dummy_engine/test/dummy/Rakefile +6 -0
- data/spec/dummy_engine/test/dummy/config.ru +4 -0
- data/spec/dummy_engine/test/dummy/config/application.rb +22 -0
- data/spec/dummy_engine/test/dummy/config/boot.rb +5 -0
- data/spec/dummy_engine/test/dummy/config/database.yml +25 -0
- data/spec/dummy_engine/test/dummy/config/environment.rb +5 -0
- data/spec/dummy_engine/test/dummy/config/environments/development.rb +37 -0
- data/spec/dummy_engine/test/dummy/config/environments/production.rb +78 -0
- data/spec/dummy_engine/test/dummy/config/environments/test.rb +39 -0
- data/spec/dummy_engine/test/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy_engine/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy_engine/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy_engine/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy_engine/test/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy_engine/test/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy_engine/test/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy_engine/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy_engine/test/dummy/config/locales/en.yml +23 -0
- data/spec/dummy_engine/test/dummy/config/routes.rb +56 -0
- data/spec/dummy_engine/test/dummy/config/secrets.yml +22 -0
- data/spec/examples/connection_adapter_examples.rb +5 -5
- data/spec/examples/generic_adapter_examples.rb +75 -37
- data/spec/examples/schema_adapter_examples.rb +19 -24
- data/spec/integration/query_caching_spec.rb +3 -3
- data/spec/integration/use_within_an_engine_spec.rb +28 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/setup.rb +9 -9
- data/spec/{database_spec.rb → tenant_spec.rb} +20 -30
- data/spec/unit/config_spec.rb +2 -2
- data/spec/unit/elevators/domain_spec.rb +1 -1
- data/spec/unit/elevators/generic_spec.rb +2 -2
- data/spec/unit/elevators/host_hash_spec.rb +5 -5
- data/spec/unit/elevators/subdomain_spec.rb +2 -2
- data/spec/unit/migrator_spec.rb +7 -7
- metadata +104 -43
@@ -13,6 +13,12 @@ module Apartment
|
|
13
13
|
module Adapters
|
14
14
|
class Mysql2Adapter < AbstractAdapter
|
15
15
|
|
16
|
+
def initialize(config)
|
17
|
+
super
|
18
|
+
|
19
|
+
@default_tenant = config[:database]
|
20
|
+
end
|
21
|
+
|
16
22
|
protected
|
17
23
|
|
18
24
|
# Connect to new tenant
|
@@ -25,13 +31,11 @@ module Apartment
|
|
25
31
|
super
|
26
32
|
rescue Mysql2::Error
|
27
33
|
Apartment::Tenant.reset
|
28
|
-
raise
|
34
|
+
raise TenantNotFound, "Cannot find tenant #{environmentify(tenant)}"
|
29
35
|
end
|
30
36
|
end
|
31
37
|
|
32
38
|
class Mysql2SchemaAdapter < AbstractAdapter
|
33
|
-
attr_reader :default_tenant
|
34
|
-
|
35
39
|
def initialize(config)
|
36
40
|
super
|
37
41
|
|
@@ -39,7 +43,7 @@ module Apartment
|
|
39
43
|
reset
|
40
44
|
end
|
41
45
|
|
42
|
-
# Reset
|
46
|
+
# Reset current tenant to the default_tenant
|
43
47
|
#
|
44
48
|
def reset
|
45
49
|
Apartment.connection.execute "use #{default_tenant}"
|
@@ -53,7 +57,7 @@ module Apartment
|
|
53
57
|
|
54
58
|
protected
|
55
59
|
|
56
|
-
#
|
60
|
+
# Connect to new tenant
|
57
61
|
#
|
58
62
|
def connect_to_new(tenant)
|
59
63
|
return reset if tenant.nil?
|
@@ -62,7 +66,7 @@ module Apartment
|
|
62
66
|
|
63
67
|
rescue ActiveRecord::StatementInvalid
|
64
68
|
Apartment::Tenant.reset
|
65
|
-
raise
|
69
|
+
raise TenantNotFound, "Cannot find tenant #{environmentify(tenant)}"
|
66
70
|
end
|
67
71
|
|
68
72
|
def process_excluded_model(model)
|
@@ -20,7 +20,7 @@ module Apartment
|
|
20
20
|
Apartment.connection.execute(%{DROP DATABASE "#{tenant}"})
|
21
21
|
|
22
22
|
rescue *rescuable_exceptions
|
23
|
-
raise
|
23
|
+
raise TenantNotFound, "The tenant #{tenant} cannot be found"
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
@@ -47,7 +47,7 @@ module Apartment
|
|
47
47
|
Apartment.connection.execute(%{DROP SCHEMA "#{tenant}" CASCADE})
|
48
48
|
|
49
49
|
rescue *rescuable_exceptions
|
50
|
-
raise
|
50
|
+
raise TenantNotFound, "The schema #{tenant.inspect} cannot be found."
|
51
51
|
end
|
52
52
|
|
53
53
|
# Reset search path to default search_path
|
@@ -59,7 +59,7 @@ module Apartment
|
|
59
59
|
# Ensure that if a schema *was* set, we override
|
60
60
|
table_name = klass.table_name.split('.', 2).last
|
61
61
|
|
62
|
-
klass.table_name = "#{
|
62
|
+
klass.table_name = "#{default_tenant}.#{table_name}"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
@@ -69,12 +69,12 @@ module Apartment
|
|
69
69
|
# @return {String} default schema search path
|
70
70
|
#
|
71
71
|
def reset
|
72
|
-
@
|
72
|
+
@current = default_tenant
|
73
73
|
Apartment.connection.schema_search_path = full_search_path
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
77
|
-
@
|
76
|
+
def current
|
77
|
+
@current || default_tenant
|
78
78
|
end
|
79
79
|
|
80
80
|
protected
|
@@ -85,11 +85,11 @@ module Apartment
|
|
85
85
|
return reset if tenant.nil?
|
86
86
|
raise ActiveRecord::StatementInvalid.new("Could not find schema #{tenant}") unless Apartment.connection.schema_exists? tenant
|
87
87
|
|
88
|
-
@
|
88
|
+
@current = tenant.to_s
|
89
89
|
Apartment.connection.schema_search_path = full_search_path
|
90
90
|
|
91
91
|
rescue *rescuable_exceptions
|
92
|
-
raise
|
92
|
+
raise TenantNotFound, "One of the following schema(s) is invalid: \"#{tenant}\" #{full_search_path}"
|
93
93
|
end
|
94
94
|
|
95
95
|
# Create the new schema
|
@@ -98,7 +98,7 @@ module Apartment
|
|
98
98
|
Apartment.connection.execute(%{CREATE SCHEMA "#{tenant}"})
|
99
99
|
|
100
100
|
rescue *rescuable_exceptions
|
101
|
-
raise
|
101
|
+
raise TenantExists, "The schema #{tenant} already exists."
|
102
102
|
end
|
103
103
|
|
104
104
|
private
|
@@ -110,7 +110,7 @@ module Apartment
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def persistent_schemas
|
113
|
-
[@
|
113
|
+
[@current, Apartment.persistent_schemas].flatten
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -155,9 +155,9 @@ module Apartment
|
|
155
155
|
# .map! {|t| "-T #{t}"}
|
156
156
|
# .join(' ')
|
157
157
|
|
158
|
-
# `pg_dump -s -x -O -n #{
|
158
|
+
# `pg_dump -s -x -O -n #{default_tenant} #{excluded_tables} #{dbname}`
|
159
159
|
|
160
|
-
`pg_dump -s -x -O -n #{
|
160
|
+
`pg_dump -s -x -O -n #{default_tenant} #{dbname}`
|
161
161
|
end
|
162
162
|
|
163
163
|
# Dump data from schema_migrations table
|
@@ -165,7 +165,7 @@ module Apartment
|
|
165
165
|
# @return {String} raw SQL contaning inserts with data from schema_migrations
|
166
166
|
#
|
167
167
|
def pg_dump_schema_migrations_data
|
168
|
-
`pg_dump -a --inserts -t schema_migrations -n #{
|
168
|
+
`pg_dump -a --inserts -t schema_migrations -n #{default_tenant} #{dbname}`
|
169
169
|
end
|
170
170
|
|
171
171
|
# Remove "SET search_path ..." line from SQL dump and prepend search_path set to current tenant
|
@@ -173,7 +173,7 @@ module Apartment
|
|
173
173
|
# @return {String} patched raw SQL dump
|
174
174
|
#
|
175
175
|
def patch_search_path(sql)
|
176
|
-
search_path = "SET search_path = \"#{current}\", #{
|
176
|
+
search_path = "SET search_path = \"#{current}\", #{default_tenant};"
|
177
177
|
|
178
178
|
sql
|
179
179
|
.split("\n")
|
@@ -199,13 +199,7 @@ module Apartment
|
|
199
199
|
# Convenience method for current database name
|
200
200
|
#
|
201
201
|
def dbname
|
202
|
-
|
203
|
-
end
|
204
|
-
|
205
|
-
# Convenience method for the default schema
|
206
|
-
#
|
207
|
-
def default_schema
|
208
|
-
Apartment.default_schema
|
202
|
+
Apartment.connection_config[:database]
|
209
203
|
end
|
210
204
|
end
|
211
205
|
end
|
@@ -16,27 +16,27 @@ module Apartment
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def drop(tenant)
|
19
|
-
raise
|
19
|
+
raise TenantNotFound,
|
20
20
|
"The tenant #{environmentify(tenant)} cannot be found." unless File.exists?(database_file(tenant))
|
21
21
|
|
22
22
|
File.delete(database_file(tenant))
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
25
|
+
def current
|
26
26
|
File.basename(Apartment.connection.instance_variable_get(:@config)[:database], '.sqlite3')
|
27
27
|
end
|
28
28
|
|
29
29
|
protected
|
30
30
|
|
31
31
|
def connect_to_new(tenant)
|
32
|
-
raise
|
32
|
+
raise TenantNotFound,
|
33
33
|
"The tenant #{environmentify(tenant)} cannot be found." unless File.exists?(database_file(tenant))
|
34
34
|
|
35
35
|
super database_file(tenant)
|
36
36
|
end
|
37
37
|
|
38
38
|
def create_tenant(tenant)
|
39
|
-
raise
|
39
|
+
raise TenantExists,
|
40
40
|
"The tenant #{environmentify(tenant)} already exists." if File.exists?(database_file(tenant))
|
41
41
|
|
42
42
|
f = File.new(database_file(tenant), File::CREAT)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rack/request'
|
2
2
|
require 'apartment/tenant'
|
3
|
+
require 'apartment/deprecation'
|
3
4
|
|
4
5
|
module Apartment
|
5
6
|
module Elevators
|
@@ -17,7 +18,7 @@ module Apartment
|
|
17
18
|
|
18
19
|
database = @processor.call(request)
|
19
20
|
|
20
|
-
Apartment::Tenant.switch database if database
|
21
|
+
Apartment::Tenant.switch! database if database
|
21
22
|
|
22
23
|
@app.call(env)
|
23
24
|
end
|
@@ -41,7 +42,7 @@ module Apartment
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def deprecation_warning
|
44
|
-
warn "[DEPRECATED::Apartment] Use #parse_tenant_name instead of #parse_database_name -> #{self.class.name}"
|
45
|
+
Apartment::Deprecation.warn "[DEPRECATED::Apartment] Use #parse_tenant_name instead of #parse_database_name -> #{self.class.name}"
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
data/lib/apartment/migrator.rb
CHANGED
@@ -7,7 +7,7 @@ module Apartment
|
|
7
7
|
|
8
8
|
# Migrate to latest
|
9
9
|
def migrate(database)
|
10
|
-
Tenant.
|
10
|
+
Tenant.switch(database) do
|
11
11
|
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
12
12
|
|
13
13
|
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, version) do |migration|
|
@@ -18,14 +18,14 @@ module Apartment
|
|
18
18
|
|
19
19
|
# Migrate up/down to a specific version
|
20
20
|
def run(direction, database, version)
|
21
|
-
Tenant.
|
21
|
+
Tenant.switch(database) do
|
22
22
|
ActiveRecord::Migrator.run(direction, ActiveRecord::Migrator.migrations_paths, version)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
# rollback latest migration `step` number of times
|
27
27
|
def rollback(database, step = 1)
|
28
|
-
Tenant.
|
28
|
+
Tenant.switch(database) do
|
29
29
|
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
|
30
30
|
end
|
31
31
|
end
|
@@ -1,26 +1,36 @@
|
|
1
1
|
# Require this file to append Apartment rake tasks to ActiveRecord db rake tasks
|
2
2
|
# Enabled by default in the initializer
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
module Apartment
|
5
|
+
class RakeTaskEnhancer
|
6
|
+
|
7
|
+
TASKS = %w(db:migrate db:rollback db:migrate:up db:migrate:down db:migrate:redo db:seed)
|
8
|
+
|
9
|
+
# This is a bit convoluted, but helps solve problems when using Apartment within an engine
|
10
|
+
# See spec/integration/use_within_an_engine.rb
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def enhance!
|
14
|
+
TASKS.each do |name|
|
15
|
+
task = Rake::Task[name]
|
16
|
+
task.enhance do
|
17
|
+
if should_enhance?
|
18
|
+
enhance_task(task)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def should_enhance?
|
25
|
+
Apartment.db_migrate_tenants
|
26
|
+
end
|
27
|
+
|
28
|
+
def enhance_task(task)
|
29
|
+
Rake::Task[task.name.sub(/db:/, 'apartment:')].invoke
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
6
34
|
end
|
7
35
|
|
8
|
-
|
9
|
-
Rake::Task["apartment:rollback"].invoke
|
10
|
-
end
|
11
|
-
|
12
|
-
Rake::Task["db:migrate:up"].enhance do
|
13
|
-
Rake::Task["apartment:migrate:up"].invoke
|
14
|
-
end
|
15
|
-
|
16
|
-
Rake::Task["db:migrate:down"].enhance do
|
17
|
-
Rake::Task["apartment:migrate:down"].invoke
|
18
|
-
end
|
19
|
-
|
20
|
-
Rake::Task["db:migrate:redo"].enhance do
|
21
|
-
Rake::Task["apartment:migrate:redo"].invoke
|
22
|
-
end
|
23
|
-
|
24
|
-
Rake::Task["db:seed"].enhance do
|
25
|
-
Rake::Task["apartment:seed"].invoke
|
26
|
-
end
|
36
|
+
Apartment::RakeTaskEnhancer.enhance!
|
data/lib/apartment/tenant.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'forwardable'
|
2
|
+
require 'apartment/deprecation'
|
2
3
|
|
3
4
|
module Apartment
|
4
5
|
# The main entry point to Apartment functions
|
@@ -8,7 +9,7 @@ module Apartment
|
|
8
9
|
extend self
|
9
10
|
extend Forwardable
|
10
11
|
|
11
|
-
def_delegators :adapter, :create, :current_tenant, :current, :current_database, :drop, :
|
12
|
+
def_delegators :adapter, :create, :current_tenant, :current, :current_database, :default_tenant, :drop, :switch, :process_excluded_models, :reset, :seed, :switch!
|
12
13
|
|
13
14
|
attr_writer :config
|
14
15
|
|
@@ -60,14 +61,16 @@ module Apartment
|
|
60
61
|
# Fetch the rails database configuration
|
61
62
|
#
|
62
63
|
def config
|
63
|
-
@config ||=
|
64
|
-
Rails.application.config.database_configuration[Rails.env]).symbolize_keys
|
64
|
+
@config ||= Apartment.connection_config
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
68
|
def self.const_missing(const_name)
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
if const_name == :Database
|
70
|
+
Apartment::Deprecation.warn "`Apartment::Database` has been deprecated. Use `Apartment::Tenant` instead."
|
71
|
+
Tenant
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
72
75
|
end
|
73
|
-
end
|
76
|
+
end
|
data/lib/apartment/version.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# You can have Apartment route to the appropriate Tenant by adding some Rack middleware.
|
2
|
+
# Apartment can support many different "Elevators" that can take care of this routing to your data.
|
3
|
+
# Require whichever Elevator you're using below or none if you have a custom one.
|
2
4
|
#
|
3
5
|
# require 'apartment/elevators/generic'
|
4
6
|
# require 'apartment/elevators/domain'
|
@@ -9,40 +11,57 @@ require 'apartment/elevators/subdomain'
|
|
9
11
|
#
|
10
12
|
Apartment.configure do |config|
|
11
13
|
|
12
|
-
#
|
13
|
-
#
|
14
|
+
# Add any models that you do not want to be multi-tenanted, but remain in the global (public) namespace.
|
15
|
+
# A typical example would be a Customer or Tenant model that stores each Tenant's information.
|
14
16
|
#
|
15
|
-
#
|
16
|
-
|
17
|
+
# config.excluded_models = %w{ Tenant }
|
18
|
+
|
19
|
+
# In order to migrate all of your Tenants you need to provide a list of Tenant names to Apartment.
|
20
|
+
# You can make this dynamic by providing a Proc object to be called on migrations.
|
21
|
+
# This object should yield an array of strings representing each Tenant name.
|
17
22
|
#
|
18
|
-
# config.
|
23
|
+
# config.tenant_names = lambda{ Customer.pluck(:tenant_name) }
|
24
|
+
# config.tenant_names = ['tenant1', 'tenant2']
|
19
25
|
#
|
20
|
-
config.
|
26
|
+
config.tenant_names = lambda { ToDo_Tenant_Or_User_Model.pluck :database }
|
21
27
|
|
22
|
-
#
|
23
|
-
|
28
|
+
#
|
29
|
+
# ==> PostgreSQL only options
|
24
30
|
|
25
|
-
#
|
26
|
-
#
|
31
|
+
# Specifies whether to use PostgreSQL schemas or create a new database per Tenant.
|
32
|
+
# The default behaviour is true.
|
33
|
+
#
|
34
|
+
# config.use_schemas = true
|
35
|
+
|
36
|
+
# Apartment can be forced to use raw SQL dumps instead of schema.rb for creating new schemas.
|
37
|
+
# Use this when you are using some extra features in PostgreSQL that can't be respresented in
|
38
|
+
# schema.rb, like materialized views etc. (only applies with use_schemas set to true).
|
39
|
+
# (Note: this option doesn't use db/structure.sql, it creates SQL dump by executing pg_dump)
|
40
|
+
#
|
41
|
+
# config.use_sql = false
|
27
42
|
|
28
|
-
#
|
43
|
+
# There are cases where you might want some schemas to always be in your search_path
|
44
|
+
# e.g when using a PostgreSQL extension like hstore.
|
45
|
+
# Any schemas added here will be available along with your selected Tenant.
|
46
|
+
#
|
29
47
|
# config.persistent_schemas = %w{ hstore }
|
30
48
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# config.append_environment = true
|
49
|
+
# <== PostgreSQL only options
|
50
|
+
#
|
34
51
|
|
35
|
-
#
|
36
|
-
|
52
|
+
# By default, and only when not using PostgreSQL schemas, Apartment will prepend the environment
|
53
|
+
# to the tenant name to ensure there is no conflict between your environments.
|
54
|
+
# This is mainly for the benefit of your development and test environments.
|
55
|
+
# Uncomment the line below if you want to disable this behaviour in production.
|
56
|
+
#
|
57
|
+
# config.prepend_environment = !Rails.env.production?
|
37
58
|
end
|
38
59
|
|
39
|
-
|
40
|
-
#
|
41
|
-
|
60
|
+
# Setup a custom Tenant switching middleware. The Proc should return the name of the Tenant that
|
61
|
+
# you want to switch to.
|
42
62
|
# Rails.application.config.middleware.use 'Apartment::Elevators::Generic', lambda { |request|
|
43
|
-
#
|
63
|
+
# request.host.split('.').first
|
44
64
|
# }
|
45
65
|
|
46
66
|
# Rails.application.config.middleware.use 'Apartment::Elevators::Domain'
|
47
|
-
|
48
67
|
Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'
|