cell 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|