ros-apartment 3.1.0 → 3.3.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/.gitignore +1 -0
- data/.rubocop.yml +142 -8
- data/.ruby-version +1 -1
- data/Appraisals +125 -30
- data/CLAUDE.md +210 -0
- data/CODE_OF_CONDUCT.md +71 -0
- data/Gemfile +15 -0
- data/README.md +49 -31
- data/Rakefile +44 -25
- data/docs/adapters.md +177 -0
- data/docs/architecture.md +274 -0
- data/docs/elevators.md +226 -0
- data/docs/images/log_example.png +0 -0
- data/lib/apartment/CLAUDE.md +300 -0
- data/lib/apartment/active_record/connection_handling.rb +2 -2
- data/lib/apartment/active_record/postgres/schema_dumper.rb +20 -0
- data/lib/apartment/active_record/postgresql_adapter.rb +19 -4
- data/lib/apartment/adapters/CLAUDE.md +314 -0
- data/lib/apartment/adapters/abstract_adapter.rb +24 -15
- data/lib/apartment/adapters/jdbc_mysql_adapter.rb +1 -1
- data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +3 -3
- data/lib/apartment/adapters/mysql2_adapter.rb +2 -2
- data/lib/apartment/adapters/postgresql_adapter.rb +55 -36
- data/lib/apartment/adapters/sqlite3_adapter.rb +7 -7
- data/lib/apartment/console.rb +1 -1
- data/lib/apartment/custom_console.rb +7 -7
- data/lib/apartment/deprecation.rb +2 -5
- data/lib/apartment/elevators/CLAUDE.md +292 -0
- data/lib/apartment/elevators/domain.rb +1 -1
- data/lib/apartment/elevators/generic.rb +1 -1
- data/lib/apartment/elevators/host_hash.rb +3 -3
- data/lib/apartment/elevators/subdomain.rb +9 -5
- data/lib/apartment/log_subscriber.rb +1 -1
- data/lib/apartment/migrator.rb +17 -5
- data/lib/apartment/model.rb +1 -1
- data/lib/apartment/railtie.rb +3 -3
- data/lib/apartment/tasks/enhancements.rb +1 -1
- data/lib/apartment/tasks/task_helper.rb +6 -4
- data/lib/apartment/tenant.rb +3 -3
- data/lib/apartment/version.rb +1 -1
- data/lib/apartment.rb +23 -11
- data/lib/generators/apartment/install/install_generator.rb +1 -1
- data/lib/generators/apartment/install/templates/apartment.rb +2 -2
- data/lib/tasks/apartment.rake +25 -25
- data/ros-apartment.gemspec +10 -35
- metadata +44 -245
- data/.rubocop_todo.yml +0 -439
- /data/{CHANGELOG.md → legacy_CHANGELOG.md} +0 -0
|
@@ -5,6 +5,7 @@ module Apartment
|
|
|
5
5
|
# Abstract adapter from which all the Apartment DB related adapters will inherit the base logic
|
|
6
6
|
class AbstractAdapter
|
|
7
7
|
include ActiveSupport::Callbacks
|
|
8
|
+
|
|
8
9
|
define_callbacks :create, :switch
|
|
9
10
|
|
|
10
11
|
attr_writer :default_tenant
|
|
@@ -21,7 +22,7 @@ module Apartment
|
|
|
21
22
|
# @param {String} tenant Tenant name
|
|
22
23
|
#
|
|
23
24
|
def create(tenant)
|
|
24
|
-
run_callbacks
|
|
25
|
+
run_callbacks(:create) do
|
|
25
26
|
create_tenant(tenant)
|
|
26
27
|
|
|
27
28
|
switch(tenant) do
|
|
@@ -72,7 +73,7 @@ module Apartment
|
|
|
72
73
|
# @param {String} tenant name
|
|
73
74
|
#
|
|
74
75
|
def switch!(tenant = nil)
|
|
75
|
-
run_callbacks
|
|
76
|
+
run_callbacks(:switch) do
|
|
76
77
|
connect_to_new(tenant).tap do
|
|
77
78
|
Apartment.connection.clear_query_cache
|
|
78
79
|
end
|
|
@@ -88,9 +89,11 @@ module Apartment
|
|
|
88
89
|
switch!(tenant)
|
|
89
90
|
yield
|
|
90
91
|
ensure
|
|
92
|
+
# Always attempt rollback to previous tenant, even if block raised
|
|
91
93
|
begin
|
|
92
94
|
switch!(previous_tenant)
|
|
93
95
|
rescue StandardError => _e
|
|
96
|
+
# If rollback fails (tenant was dropped, connection lost), fall back to default
|
|
94
97
|
reset
|
|
95
98
|
end
|
|
96
99
|
end
|
|
@@ -99,7 +102,7 @@ module Apartment
|
|
|
99
102
|
#
|
|
100
103
|
def each(tenants = Apartment.tenant_names)
|
|
101
104
|
tenants.each do |tenant|
|
|
102
|
-
switch(tenant) { yield
|
|
105
|
+
switch(tenant) { yield(tenant) }
|
|
103
106
|
end
|
|
104
107
|
end
|
|
105
108
|
|
|
@@ -116,7 +119,7 @@ module Apartment
|
|
|
116
119
|
# Reset the tenant connection to the default
|
|
117
120
|
#
|
|
118
121
|
def reset
|
|
119
|
-
Apartment.establish_connection
|
|
122
|
+
Apartment.establish_connection(@config)
|
|
120
123
|
end
|
|
121
124
|
|
|
122
125
|
# Load the rails seed file into the db
|
|
@@ -147,7 +150,7 @@ module Apartment
|
|
|
147
150
|
protected
|
|
148
151
|
|
|
149
152
|
def process_excluded_model(excluded_model)
|
|
150
|
-
excluded_model.constantize.establish_connection
|
|
153
|
+
excluded_model.constantize.establish_connection(@config)
|
|
151
154
|
end
|
|
152
155
|
|
|
153
156
|
def drop_command(conn, tenant)
|
|
@@ -178,11 +181,14 @@ module Apartment
|
|
|
178
181
|
def connect_to_new(tenant)
|
|
179
182
|
return reset if tenant.nil?
|
|
180
183
|
|
|
184
|
+
# Preserve query cache state across tenant switches
|
|
185
|
+
# Rails disables it during connection establishment
|
|
181
186
|
query_cache_enabled = ActiveRecord::Base.connection.query_cache_enabled
|
|
182
187
|
|
|
183
|
-
Apartment.establish_connection
|
|
184
|
-
Apartment.connection.
|
|
188
|
+
Apartment.establish_connection(multi_tenantify(tenant))
|
|
189
|
+
Apartment.connection.verify! # Explicitly validate connection is live
|
|
185
190
|
|
|
191
|
+
# Restore query cache if it was previously enabled
|
|
186
192
|
Apartment.connection.enable_query_cache! if query_cache_enabled
|
|
187
193
|
rescue *rescuable_exceptions => e
|
|
188
194
|
Apartment::Tenant.reset if reset_on_connection_exception?
|
|
@@ -216,7 +222,7 @@ module Apartment
|
|
|
216
222
|
# Load a file or raise error if it doesn't exists
|
|
217
223
|
#
|
|
218
224
|
def load_or_raise(file)
|
|
219
|
-
raise
|
|
225
|
+
raise(FileNotFound, "#{file} doesn't exist yet") unless File.exist?(file)
|
|
220
226
|
|
|
221
227
|
load(file)
|
|
222
228
|
end
|
|
@@ -239,15 +245,16 @@ module Apartment
|
|
|
239
245
|
Apartment.db_config_for(tenant).dup
|
|
240
246
|
end
|
|
241
247
|
|
|
242
|
-
def with_neutral_connection(tenant, &
|
|
248
|
+
def with_neutral_connection(tenant, &)
|
|
243
249
|
if Apartment.with_multi_server_setup
|
|
244
|
-
#
|
|
245
|
-
#
|
|
246
|
-
#
|
|
250
|
+
# Multi-server setup requires separate connection handler to avoid polluting
|
|
251
|
+
# the main connection pool. For example: connecting to postgres 'template1'
|
|
252
|
+
# database to CREATE/DROP tenant databases without affecting app connections.
|
|
247
253
|
SeparateDbConnectionHandler.establish_connection(multi_tenantify(tenant, false))
|
|
248
254
|
yield(SeparateDbConnectionHandler.connection)
|
|
249
255
|
SeparateDbConnectionHandler.connection.close
|
|
250
256
|
else
|
|
257
|
+
# Single-server: reuse existing connection (safe for most operations)
|
|
251
258
|
yield(Apartment.connection)
|
|
252
259
|
end
|
|
253
260
|
end
|
|
@@ -257,17 +264,19 @@ module Apartment
|
|
|
257
264
|
end
|
|
258
265
|
|
|
259
266
|
def raise_drop_tenant_error!(tenant, exception)
|
|
260
|
-
raise
|
|
267
|
+
raise(TenantNotFound, "Error while dropping tenant #{environmentify(tenant)}: #{exception.message}")
|
|
261
268
|
end
|
|
262
269
|
|
|
263
270
|
def raise_create_tenant_error!(tenant, exception)
|
|
264
|
-
raise
|
|
271
|
+
raise(TenantExists, "Error while creating tenant #{environmentify(tenant)}: #{exception.message}")
|
|
265
272
|
end
|
|
266
273
|
|
|
267
274
|
def raise_connect_error!(tenant, exception)
|
|
268
|
-
raise
|
|
275
|
+
raise(TenantNotFound, "Error while connecting to tenant #{environmentify(tenant)}: #{exception.message}")
|
|
269
276
|
end
|
|
270
277
|
|
|
278
|
+
# Dedicated AR connection class for neutral connections (admin operations like CREATE/DROP DATABASE).
|
|
279
|
+
# Prevents admin commands from polluting the main application connection pool.
|
|
271
280
|
class SeparateDbConnectionHandler < ::ActiveRecord::Base
|
|
272
281
|
end
|
|
273
282
|
end
|
|
@@ -38,12 +38,12 @@ module Apartment
|
|
|
38
38
|
#
|
|
39
39
|
def connect_to_new(tenant = nil)
|
|
40
40
|
return reset if tenant.nil?
|
|
41
|
-
raise
|
|
41
|
+
raise(ActiveRecord::StatementInvalid, "Could not find schema #{tenant}") unless schema_exists?(tenant)
|
|
42
42
|
|
|
43
43
|
@current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s
|
|
44
44
|
Apartment.connection.schema_search_path = full_search_path
|
|
45
45
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::JDBCError
|
|
46
|
-
raise
|
|
46
|
+
raise(TenantNotFound, "One of the following schema(s) is invalid: #{full_search_path}")
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
private
|
|
@@ -51,7 +51,7 @@ module Apartment
|
|
|
51
51
|
def tenant_exists?(tenant)
|
|
52
52
|
return true unless Apartment.tenant_presence_check
|
|
53
53
|
|
|
54
|
-
Apartment.connection.all_schemas.include?
|
|
54
|
+
Apartment.connection.all_schemas.include?(tenant)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def rescue_from
|
|
@@ -44,7 +44,7 @@ module Apartment
|
|
|
44
44
|
def reset
|
|
45
45
|
return unless default_tenant
|
|
46
46
|
|
|
47
|
-
Apartment.connection.execute
|
|
47
|
+
Apartment.connection.execute("use `#{default_tenant}`")
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
protected
|
|
@@ -54,7 +54,7 @@ module Apartment
|
|
|
54
54
|
def connect_to_new(tenant)
|
|
55
55
|
return reset if tenant.nil?
|
|
56
56
|
|
|
57
|
-
Apartment.connection.execute
|
|
57
|
+
Apartment.connection.execute("use `#{environmentify(tenant)}`")
|
|
58
58
|
rescue ActiveRecord::StatementInvalid => e
|
|
59
59
|
Apartment::Tenant.reset
|
|
60
60
|
raise_connect_error!(tenant, e)
|
|
@@ -57,7 +57,8 @@ module Apartment
|
|
|
57
57
|
|
|
58
58
|
def process_excluded_model(excluded_model)
|
|
59
59
|
excluded_model.constantize.tap do |klass|
|
|
60
|
-
#
|
|
60
|
+
# Strip any existing schema qualifier (handles "schema.table" → "table")
|
|
61
|
+
# Then explicitly set to default schema to prevent tenant-based queries
|
|
61
62
|
table_name = klass.table_name.split('.', 2).last
|
|
62
63
|
|
|
63
64
|
klass.table_name = "#{default_tenant}.#{table_name}"
|
|
@@ -72,15 +73,10 @@ module Apartment
|
|
|
72
73
|
#
|
|
73
74
|
def connect_to_new(tenant = nil)
|
|
74
75
|
return reset if tenant.nil?
|
|
75
|
-
raise
|
|
76
|
+
raise(ActiveRecord::StatementInvalid, "Could not find schema #{tenant}") unless schema_exists?(tenant)
|
|
76
77
|
|
|
77
78
|
@current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s
|
|
78
79
|
Apartment.connection.schema_search_path = full_search_path
|
|
79
|
-
|
|
80
|
-
# When the PostgreSQL version is < 9.3,
|
|
81
|
-
# there is a issue for prepared statement with changing search_path.
|
|
82
|
-
# https://www.postgresql.org/docs/9.3/static/sql-prepare.html
|
|
83
|
-
Apartment.connection.clear_cache! if postgresql_version < 90_300
|
|
84
80
|
rescue *rescuable_exceptions => e
|
|
85
81
|
raise_schema_connect_to_new(tenant, e)
|
|
86
82
|
end
|
|
@@ -94,7 +90,8 @@ module Apartment
|
|
|
94
90
|
end
|
|
95
91
|
|
|
96
92
|
def create_tenant_command(conn, tenant)
|
|
97
|
-
#
|
|
93
|
+
# Avoid nested transactions: if already in transaction (e.g., RSpec tests),
|
|
94
|
+
# execute directly. Otherwise, wrap in explicit transaction for atomicity.
|
|
98
95
|
if ActiveRecord::Base.connection.open_transactions.positive?
|
|
99
96
|
conn.execute(%(CREATE SCHEMA "#{tenant}"))
|
|
100
97
|
else
|
|
@@ -106,7 +103,7 @@ module Apartment
|
|
|
106
103
|
end
|
|
107
104
|
rescue *rescuable_exceptions => e
|
|
108
105
|
rollback_transaction(conn)
|
|
109
|
-
raise
|
|
106
|
+
raise(e)
|
|
110
107
|
end
|
|
111
108
|
|
|
112
109
|
def rollback_transaction(conn)
|
|
@@ -136,7 +133,7 @@ module Apartment
|
|
|
136
133
|
end
|
|
137
134
|
|
|
138
135
|
def raise_schema_connect_to_new(tenant, exception)
|
|
139
|
-
raise
|
|
136
|
+
raise(TenantNotFound, <<~EXCEPTION_MESSAGE)
|
|
140
137
|
Could not set search path to schemas, they may be invalid: "#{tenant}" #{full_search_path}.
|
|
141
138
|
Original error: #{exception.class}: #{exception}
|
|
142
139
|
EXCEPTION_MESSAGE
|
|
@@ -151,11 +148,32 @@ module Apartment
|
|
|
151
148
|
/SET row_security/i, # new in postgresql 9.5
|
|
152
149
|
/SET idle_in_transaction_session_timeout/i, # new in postgresql 9.6
|
|
153
150
|
/SET default_table_access_method/i, # new in postgresql 12
|
|
154
|
-
/CREATE SCHEMA
|
|
155
|
-
/COMMENT ON SCHEMA
|
|
151
|
+
/CREATE SCHEMA/i,
|
|
152
|
+
/COMMENT ON SCHEMA/i,
|
|
153
|
+
/SET transaction_timeout/i, # new in postgresql 17
|
|
154
|
+
|
|
155
|
+
].freeze
|
|
156
156
|
|
|
157
|
+
# PostgreSQL meta-commands (backslash commands) that appear in pg_dump output
|
|
158
|
+
# but are not valid SQL when passed to ActiveRecord's execute().
|
|
159
|
+
# These must be filtered out to prevent syntax errors during schema import.
|
|
160
|
+
PSQL_META_COMMANDS = [
|
|
161
|
+
/^\\connect/i,
|
|
162
|
+
/^\\set/i,
|
|
163
|
+
/^\\unset/i,
|
|
164
|
+
/^\\copyright/i,
|
|
165
|
+
/^\\echo/i,
|
|
166
|
+
/^\\warn/i,
|
|
167
|
+
/^\\o/i,
|
|
168
|
+
/^\\t/i,
|
|
169
|
+
/^\\q/i,
|
|
170
|
+
/^\\./i, # Catch-all for any backslash command (e.g., \. for COPY delimiter,
|
|
171
|
+
# \restrict/\unrestrict in PostgreSQL 17.6+, and future meta-commands)
|
|
157
172
|
].freeze
|
|
158
173
|
|
|
174
|
+
# Combined blacklist: SQL statements and psql meta-commands to filter from pg_dump output
|
|
175
|
+
PSQL_DUMP_GLOBAL_BLACKLIST = (PSQL_DUMP_BLACKLISTED_STATEMENTS + PSQL_META_COMMANDS).freeze
|
|
176
|
+
|
|
159
177
|
def import_database_schema
|
|
160
178
|
preserving_search_path do
|
|
161
179
|
clone_pg_schema
|
|
@@ -165,9 +183,9 @@ module Apartment
|
|
|
165
183
|
|
|
166
184
|
private
|
|
167
185
|
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
186
|
+
# PostgreSQL's pg_dump clears search_path in the dump output, which would
|
|
187
|
+
# leave us with an empty path after import. Capture current path, execute
|
|
188
|
+
# import, then restore it to maintain tenant context.
|
|
171
189
|
#
|
|
172
190
|
def preserving_search_path
|
|
173
191
|
search_path = Apartment.connection.execute('show search_path').first['search_path']
|
|
@@ -194,15 +212,13 @@ module Apartment
|
|
|
194
212
|
# @return {String} raw SQL contaning only postgres schema dump
|
|
195
213
|
#
|
|
196
214
|
def pg_dump_schema
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
with_pg_env { `pg_dump -s -x -O -n #{default_tenant} #{dbname}` }
|
|
215
|
+
exclude_table =
|
|
216
|
+
if Apartment.pg_exclude_clone_tables
|
|
217
|
+
excluded_tables.map! { |t| "-T #{t}" }.join(' ')
|
|
218
|
+
else
|
|
219
|
+
''
|
|
220
|
+
end
|
|
221
|
+
with_pg_env { `pg_dump -s -x -O -n #{default_tenant} #{dbname} #{exclude_table}` }
|
|
206
222
|
end
|
|
207
223
|
|
|
208
224
|
# Dump data from schema_migrations table
|
|
@@ -215,13 +231,14 @@ module Apartment
|
|
|
215
231
|
end
|
|
216
232
|
# rubocop:enable Layout/LineLength
|
|
217
233
|
|
|
218
|
-
#
|
|
219
|
-
#
|
|
234
|
+
# Temporarily set PostgreSQL environment variables for pg_dump shell commands.
|
|
235
|
+
# Must preserve and restore existing ENV values to avoid polluting global state.
|
|
236
|
+
# pg_dump reads these instead of passing connection params as CLI args.
|
|
220
237
|
def with_pg_env
|
|
221
|
-
pghost = ENV
|
|
222
|
-
pgport = ENV
|
|
223
|
-
pguser = ENV
|
|
224
|
-
pgpassword = ENV
|
|
238
|
+
pghost = ENV.fetch('PGHOST', nil)
|
|
239
|
+
pgport = ENV.fetch('PGPORT', nil)
|
|
240
|
+
pguser = ENV.fetch('PGUSER', nil)
|
|
241
|
+
pgpassword = ENV.fetch('PGPASSWORD', nil)
|
|
225
242
|
|
|
226
243
|
ENV['PGHOST'] = @config[:host] if @config[:host]
|
|
227
244
|
ENV['PGPORT'] = @config[:port].to_s if @config[:port]
|
|
@@ -230,6 +247,7 @@ module Apartment
|
|
|
230
247
|
|
|
231
248
|
yield
|
|
232
249
|
ensure
|
|
250
|
+
# Always restore original ENV state (might be nil)
|
|
233
251
|
ENV['PGHOST'] = pghost
|
|
234
252
|
ENV['PGPORT'] = pgport
|
|
235
253
|
ENV['PGUSER'] = pguser
|
|
@@ -245,14 +263,15 @@ module Apartment
|
|
|
245
263
|
|
|
246
264
|
swap_schema_qualifier(sql)
|
|
247
265
|
.split("\n")
|
|
248
|
-
.
|
|
266
|
+
.grep_v(Regexp.union(PSQL_DUMP_GLOBAL_BLACKLIST))
|
|
249
267
|
.prepend(search_path)
|
|
250
268
|
.join("\n")
|
|
251
269
|
end
|
|
252
270
|
|
|
253
271
|
def swap_schema_qualifier(sql)
|
|
254
272
|
sql.gsub(/#{default_tenant}\.\w*/) do |match|
|
|
255
|
-
if Apartment.pg_excluded_names.any? { |name| match.include?
|
|
273
|
+
if Apartment.pg_excluded_names.any? { |name| match.include?(name) } ||
|
|
274
|
+
(Apartment.pg_exclude_clone_tables && excluded_tables.any?(match))
|
|
256
275
|
match
|
|
257
276
|
else
|
|
258
277
|
match.gsub("#{default_tenant}.", %("#{current}".))
|
|
@@ -263,13 +282,13 @@ module Apartment
|
|
|
263
282
|
# Checks if any of regexps matches against input
|
|
264
283
|
#
|
|
265
284
|
def check_input_against_regexps(input, regexps)
|
|
266
|
-
regexps.select { |c| input.match
|
|
285
|
+
regexps.select { |c| input.match(c) }
|
|
267
286
|
end
|
|
268
287
|
|
|
269
|
-
#
|
|
288
|
+
# Convenience method for excluded table names
|
|
270
289
|
#
|
|
271
|
-
def
|
|
272
|
-
|
|
290
|
+
def excluded_tables
|
|
291
|
+
Apartment.excluded_models.map do |m|
|
|
273
292
|
m.constantize.table_name
|
|
274
293
|
end
|
|
275
294
|
end
|
|
@@ -19,8 +19,8 @@ module Apartment
|
|
|
19
19
|
|
|
20
20
|
def drop(tenant)
|
|
21
21
|
unless File.exist?(database_file(tenant))
|
|
22
|
-
raise
|
|
23
|
-
"The tenant #{environmentify(tenant)} cannot be found."
|
|
22
|
+
raise(TenantNotFound,
|
|
23
|
+
"The tenant #{environmentify(tenant)} cannot be found.")
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
File.delete(database_file(tenant))
|
|
@@ -36,17 +36,17 @@ module Apartment
|
|
|
36
36
|
return reset if tenant.nil?
|
|
37
37
|
|
|
38
38
|
unless File.exist?(database_file(tenant))
|
|
39
|
-
raise
|
|
40
|
-
"The tenant #{environmentify(tenant)} cannot be found."
|
|
39
|
+
raise(TenantNotFound,
|
|
40
|
+
"The tenant #{environmentify(tenant)} cannot be found.")
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
super
|
|
43
|
+
super(database_file(tenant))
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def create_tenant(tenant)
|
|
47
47
|
if File.exist?(database_file(tenant))
|
|
48
|
-
raise
|
|
49
|
-
"The tenant #{environmentify(tenant)} already exists."
|
|
48
|
+
raise(TenantExists,
|
|
49
|
+
"The tenant #{environmentify(tenant)} already exists.")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
begin
|
data/lib/apartment/console.rb
CHANGED
|
@@ -4,7 +4,7 @@ def st(schema_name = nil)
|
|
|
4
4
|
if schema_name.nil?
|
|
5
5
|
tenant_list.each { |t| puts t }
|
|
6
6
|
|
|
7
|
-
elsif tenant_list.include?
|
|
7
|
+
elsif tenant_list.include?(schema_name)
|
|
8
8
|
Apartment::Tenant.switch!(schema_name)
|
|
9
9
|
else
|
|
10
10
|
puts "Tenant #{schema_name} is not part of the tenant list"
|
|
@@ -5,7 +5,7 @@ require_relative 'console'
|
|
|
5
5
|
module Apartment
|
|
6
6
|
module CustomConsole
|
|
7
7
|
begin
|
|
8
|
-
require
|
|
8
|
+
require('pry-rails')
|
|
9
9
|
rescue LoadError
|
|
10
10
|
# rubocop:disable Layout/LineLength
|
|
11
11
|
puts '[Failed to load pry-rails] If you want to use Apartment custom prompt you need to add pry-rails to your gemfile'
|
|
@@ -13,17 +13,17 @@ module Apartment
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
desc = "Includes the current Rails environment and project folder name.\n" \
|
|
16
|
-
|
|
16
|
+
'[1] [project_name][Rails.env][Apartment::Tenant.current] pry(main)>'
|
|
17
17
|
|
|
18
18
|
prompt_procs = [
|
|
19
19
|
proc { |target_self, nest_level, pry| prompt_contents(pry, target_self, nest_level, '>') },
|
|
20
|
-
proc { |target_self, nest_level, pry| prompt_contents(pry, target_self, nest_level, '*') }
|
|
20
|
+
proc { |target_self, nest_level, pry| prompt_contents(pry, target_self, nest_level, '*') },
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
if Gem::Version.new(Pry::VERSION) >= Gem::Version.new('0.13')
|
|
24
|
-
Pry.config.prompt = Pry::Prompt.new
|
|
24
|
+
Pry.config.prompt = Pry::Prompt.new('ros', desc, prompt_procs)
|
|
25
25
|
else
|
|
26
|
-
Pry::Prompt.add
|
|
26
|
+
Pry::Prompt.add('ros', desc, %w[> *]) do |target_self, nest_level, pry, sep|
|
|
27
27
|
prompt_contents(pry, target_self, nest_level, sep)
|
|
28
28
|
end
|
|
29
29
|
Pry.config.prompt = Pry::Prompt[:ros][:value]
|
|
@@ -35,8 +35,8 @@ module Apartment
|
|
|
35
35
|
|
|
36
36
|
def self.prompt_contents(pry, target_self, nest_level, sep)
|
|
37
37
|
"[#{pry.input_ring.size}] [#{PryRails::Prompt.formatted_env}][#{Apartment::Tenant.current}] " \
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
"#{pry.config.prompt_name}(#{Pry.view_clip(target_self)})" \
|
|
39
|
+
"#{":#{nest_level}" unless nest_level.zero?}#{sep} "
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'active_support/deprecation'
|
|
4
|
+
require_relative 'version'
|
|
4
5
|
|
|
5
6
|
module Apartment
|
|
6
|
-
|
|
7
|
-
def self.warn(message)
|
|
8
|
-
ActiveSupport::Deprecation.warn message
|
|
9
|
-
end
|
|
10
|
-
end
|
|
7
|
+
DEPRECATOR = ActiveSupport::Deprecation.new(Apartment::VERSION, 'Apartment')
|
|
11
8
|
end
|