cell 0.1.1 → 0.1.2
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/README.md +125 -49
- data/Rakefile +2 -1
- data/cell.gemspec +1 -1
- data/lib/cell/active_job.rb +32 -0
- data/lib/cell/clone_schema.rb +18 -16
- data/lib/cell/console.rb +9 -15
- data/lib/cell/context.rb +48 -27
- data/lib/cell/meta.rb +87 -0
- data/lib/cell/migration.rb +131 -44
- data/lib/cell/model_extensions.rb +85 -0
- data/lib/cell/railtie.rb +17 -3
- data/lib/cell/sanity_check.rb +21 -23
- data/lib/cell/schema.rb +2 -13
- data/lib/cell/tasks/cell.rake +18 -11
- data/lib/cell/tenant.rb +55 -0
- data/lib/cell/url_options.rb +26 -0
- data/lib/cell/version.rb +1 -1
- data/lib/cell.rb +1 -6
- metadata +9 -11
- data/lib/cell/configure.rb +0 -70
- data/lib/cell/data_directory.rb +0 -42
- data/lib/cell/model.rb +0 -37
- data/lib/cell/sidekiq.rb +0 -58
- data/lib/cell/with_schema.rb +0 -30
- data/lib/dump/tenant_routing_manager.rb +0 -25
- data/lib/dump/tenant_url_options.rb +0 -17
data/lib/cell/configure.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'cell/context'
|
2
|
-
require 'cell/model'
|
3
|
-
require 'cell/schema'
|
4
|
-
|
5
|
-
module Cell
|
6
|
-
class Configuration
|
7
|
-
attr_accessor :model
|
8
|
-
attr_accessor :identifier
|
9
|
-
attr_accessor :data_directory
|
10
|
-
attr_accessor :sidekiq
|
11
|
-
|
12
|
-
def initialize(model, &block)
|
13
|
-
@model = model
|
14
|
-
@identifier = :id
|
15
|
-
@data_directory = nil
|
16
|
-
@sidekiq = false
|
17
|
-
|
18
|
-
yield self
|
19
|
-
commit!(model)
|
20
|
-
end
|
21
|
-
|
22
|
-
def commit!(model)
|
23
|
-
fail "model class not specified" if model.nil? || ! model.is_a?(Class)
|
24
|
-
|
25
|
-
configure_model!(model)
|
26
|
-
configure_data_directory!(model)
|
27
|
-
configure_sidekiq!(model)
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def configure_model!(model)
|
33
|
-
->(identifier) do
|
34
|
-
model.define_singleton_method(:cell_id_column) do
|
35
|
-
identifier
|
36
|
-
end
|
37
|
-
end.call(self.identifier)
|
38
|
-
|
39
|
-
Cell.const_set(:Tenant, model)
|
40
|
-
model.prepend(::Cell::Model)
|
41
|
-
model.prepend(::Cell::Schema)
|
42
|
-
model.prepend(::Cell::Context)
|
43
|
-
end
|
44
|
-
|
45
|
-
def configure_data_directory!(model)
|
46
|
-
if self.data_directory
|
47
|
-
->(data_directory) do
|
48
|
-
model.define_singleton_method(:data_directory_root) do
|
49
|
-
data_directory
|
50
|
-
end
|
51
|
-
end.call(self.data_directory.to_s)
|
52
|
-
model.prepend(::Cell::DataDirectory)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def configure_sidekiq!(model)
|
57
|
-
if self.sidekiq
|
58
|
-
require 'cell/sidekiq'
|
59
|
-
::Cell::Sidekiq.configure!
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
private_constant :Configuration
|
64
|
-
|
65
|
-
module_function
|
66
|
-
def configure(model = nil, &block)
|
67
|
-
fail ArgumentError, "model or block required" if model.nil? && !block_given?
|
68
|
-
Configuration.new(model || block.binding.receiver, &block)
|
69
|
-
end
|
70
|
-
end
|
data/lib/cell/data_directory.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
module Cell
|
4
|
-
module DataDirectory
|
5
|
-
module ClassMethods
|
6
|
-
def data_directory_root
|
7
|
-
fail NotImplementedError
|
8
|
-
end
|
9
|
-
|
10
|
-
def data_directory_for_cell_id(cell_id)
|
11
|
-
cell_id = cell_id.to_s.gsub(/[^a-z0-9_]/i, '-')
|
12
|
-
File.join(data_directory_root, cell_id)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def data_directory
|
17
|
-
self.class.data_directory_for_cell_id(cell_id)
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
def create_data_directory!
|
22
|
-
FileUtils.mkdir_p(data_directory)
|
23
|
-
end
|
24
|
-
|
25
|
-
def update_data_directory!
|
26
|
-
src, dst = cell_id_change_set
|
27
|
-
FileUtils.mv(self.class.data_directory_for_cell_id(src), data_directory)
|
28
|
-
end
|
29
|
-
|
30
|
-
def destroy_data_directory!
|
31
|
-
FileUtils.rm_rf(data_directory)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.prepended(cls)
|
35
|
-
cls.extend(ClassMethods)
|
36
|
-
|
37
|
-
cls.after_create_commit :create_data_directory!
|
38
|
-
cls.after_update_commit :update_data_directory!, if: :cell_id_changed?
|
39
|
-
cls.after_destroy_commit :destroy_data_directory!
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/cell/model.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'cell/schema'
|
2
|
-
require 'cell/data_directory'
|
3
|
-
|
4
|
-
module Cell
|
5
|
-
module Model
|
6
|
-
class << self
|
7
|
-
attr_accessor :cls
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def cell_id_column
|
12
|
-
fail NotImplementedError
|
13
|
-
end
|
14
|
-
|
15
|
-
def cell_find(cell_id)
|
16
|
-
find_by(cell_id_column => cell_id)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def cell_id
|
21
|
-
send(self.class.cell_id_column)
|
22
|
-
end
|
23
|
-
|
24
|
-
def cell_id_changed?
|
25
|
-
!! previous_changes[self.class.cell_id_column]
|
26
|
-
end
|
27
|
-
|
28
|
-
def cell_id_change_set
|
29
|
-
fail "cell_id was not changed" unless cell_id_changed?
|
30
|
-
previous_changes[self.class.cell_id_column]
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.prepended(cls)
|
34
|
-
cls.extend(ClassMethods)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
data/lib/cell/sidekiq.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# This middleware passes along a tenant_id from client to server if a tenant
|
2
|
-
# is active when a job is spun off. The server process then activates the
|
3
|
-
# proper tenant if it's detected, so jobs are processed under the context of the
|
4
|
-
# same tenant that started the job on the client.
|
5
|
-
|
6
|
-
|
7
|
-
require 'sidekiq'
|
8
|
-
|
9
|
-
module Cell
|
10
|
-
module Sidekiq
|
11
|
-
KEY = 'Cell.cell_id'
|
12
|
-
|
13
|
-
class ClientMiddleware
|
14
|
-
def call(worker, msg, queue, redis_pool)
|
15
|
-
if (current_id = ::Cell.current&.cell_id)
|
16
|
-
msg[KEY] = current_id
|
17
|
-
end
|
18
|
-
|
19
|
-
yield
|
20
|
-
true
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class ServerMiddleware
|
25
|
-
def call(worker, msg, queue, &block)
|
26
|
-
if msg.key?(KEY)
|
27
|
-
::Cell::Tenant.use(::Cell::Tenant.cell_find(msg[KEY]), &block)
|
28
|
-
else
|
29
|
-
::Cell::Tenant.use(nil, &block)
|
30
|
-
end
|
31
|
-
|
32
|
-
true
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module_function
|
37
|
-
def configure!
|
38
|
-
::Sidekiq.configure_client do |config|
|
39
|
-
config.client_middleware do |chain|
|
40
|
-
chain.add ClientMiddleware
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
::Sidekiq.configure_server do |config|
|
45
|
-
# The server can also act as a client by creating more jobs, so we
|
46
|
-
# should configure the client inside the server block.
|
47
|
-
config.client_middleware do |chain|
|
48
|
-
chain.add ClientMiddleware
|
49
|
-
end
|
50
|
-
|
51
|
-
config.server_middleware do |chain|
|
52
|
-
chain.add ServerMiddleware
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
data/lib/cell/with_schema.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'active_record/base'
|
2
|
-
|
3
|
-
module Cell
|
4
|
-
module WithSchema
|
5
|
-
module_function
|
6
|
-
def with_schema(new_path, exclusive: false, connection:)
|
7
|
-
saved_path = connection.schema_search_path
|
8
|
-
new_path = connection.quote_schema_name(new_path)
|
9
|
-
active_path = exclusive ? new_path : "#{new_path},#{saved_path}"
|
10
|
-
|
11
|
-
set_schema_search_path(active_path, connection: connection)
|
12
|
-
|
13
|
-
if block_given?
|
14
|
-
begin
|
15
|
-
yield
|
16
|
-
ensure
|
17
|
-
set_schema_search_path(saved_path, connection: connection)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private \
|
23
|
-
def set_schema_search_path(path, connection:)
|
24
|
-
if path != connection.schema_search_path
|
25
|
-
connection.schema_search_path = path
|
26
|
-
connection.clear_query_cache
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# TenantRoutingManager contains methods that can locate URLs and such for
|
2
|
-
# a given tenant.
|
3
|
-
|
4
|
-
module TenantRoutingManager
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
class_methods do
|
8
|
-
def slug_from_host(host)
|
9
|
-
if host && (match = host.match(/\A([a-z][a-z0-9-]*)\./))
|
10
|
-
return match[1]
|
11
|
-
end
|
12
|
-
return nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def from_slug(slug)
|
16
|
-
return friendly.find(slug)
|
17
|
-
rescue ActiveRecord::RecordNotFound
|
18
|
-
return nil
|
19
|
-
end
|
20
|
-
|
21
|
-
def from_host(host)
|
22
|
-
from_slug(slug_from_host(host))
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module TenantUrlOptions
|
2
|
-
module_function \
|
3
|
-
def default_url_options
|
4
|
-
r = {}
|
5
|
-
r[:protocol] = 'https' if Rails.env.production?
|
6
|
-
r[:port] = 3000 unless Rails.env.production?
|
7
|
-
r[:host] = Tenant.current.try(:host)
|
8
|
-
r
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
class ActionMailer::Base
|
14
|
-
def default_url_options
|
15
|
-
TenantUrlOptions.default_url_options
|
16
|
-
end
|
17
|
-
end
|