Module: MultiTenant

Defined in:
lib/activerecord-multi-tenant/fast_truncate.rb,
lib/activerecord-multi-tenant/version.rb,
lib/activerecord-multi-tenant/migrations.rb,
lib/activerecord-multi-tenant/multi_tenant.rb,
lib/activerecord-multi-tenant/query_monitor.rb,
lib/activerecord-multi-tenant/query_rewriter.rb,
lib/activerecord-multi-tenant/copy_from_client.rb,
lib/activerecord-multi-tenant/model_extensions.rb,
lib/activerecord-multi-tenant/controller_extensions.rb,
lib/activerecord-multi-tenant/arel_visitors_depth_first.rb

Overview

Add generic warning when queries fail and there is no tenant set

Defined Under Namespace

Modules: ControllerExtensions, CopyFromClient, DatabaseStatements, FastTruncate, MigrationExtensions, ModelExtensionsClassMethods, TenantValueVisitor Classes: ArelTenantVisitor, ArelVisitorsDepthFirst, BaseTenantEnforcementClause, Context, CopyFromClientHelper, QueryMonitor, Table, TenantEnforcementClause, TenantIsImmutable, TenantJoinEnforcementClause

Constant Summary collapse

VERSION =
'1.2.0'
@@enable_with_lock_workaround =

Workaroud to make “with_lock” work until github.com/citusdata/citus/issues/1236 is fixed

false
@@enable_query_monitor =

Option to enable query monitor

false

Class Method Summary collapse

Class Method Details

.current_tenantObject



49
50
51
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 49

def self.current_tenant
  RequestStore.store[:current_tenant]
end

.current_tenant=(tenant) ⇒ Object



45
46
47
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 45

def self.current_tenant=(tenant)
  RequestStore.store[:current_tenant] = tenant
end

.current_tenant_classObject



61
62
63
64
65
66
67
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 61

def self.current_tenant_class
  if current_tenant_is_id?
    MultiTenant.default_tenant_class || fail('Only have tenant id, and no default tenant class set')
  elsif current_tenant
    MultiTenant.current_tenant.class.name
  end
end

.current_tenant_idObject



53
54
55
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 53

def self.current_tenant_id
  current_tenant_is_id? ? current_tenant : current_tenant.try(:id)
end

.current_tenant_is_id?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 57

def self.current_tenant_is_id?
  current_tenant.is_a?(String) || current_tenant.is_a?(Integer)
end

.default_tenant_classObject



14
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 14

def self.default_tenant_class; @@default_tenant_class ||= nil; end

.default_tenant_class=(tenant_class) ⇒ Object

In some cases we only have an ID - if defined we'll return the default tenant class in such cases



13
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 13

def self.default_tenant_class=(tenant_class); @@default_tenant_class = tenant_class; end

.enable_query_monitorObject



5
# File 'lib/activerecord-multi-tenant/query_monitor.rb', line 5

def self.enable_query_monitor; @@enable_query_monitor = true; end

.enable_with_lock_workaroundObject



23
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 23

def self.enable_with_lock_workaround; @@enable_with_lock_workaround = true; end

.enable_write_only_modeObject

Write-only Mode - this only adds the tenant_id to new records, but doesn't require its presence for SELECTs/UPDATEs/DELETEs



18
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 18

def self.enable_write_only_mode; @@enable_write_only_mode = true; end

.load_current_tenant!Object



69
70
71
72
73
74
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 69

def self.load_current_tenant!
  return MultiTenant.current_tenant if MultiTenant.current_tenant && !current_tenant_is_id?
  raise 'MultiTenant.current_tenant must be set to load' if MultiTenant.current_tenant.nil?
  klass = MultiTenant.default_tenant_class || fail('Only have tenant id, and no default tenant class set')
  self.current_tenant = klass.find(MultiTenant.current_tenant_id)
end

.multi_tenant_model_for_arel(arel) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 36

def self.multi_tenant_model_for_arel(arel)
  return nil unless arel.respond_to?(:ast)
  if arel.ast.relation.is_a? Arel::Nodes::JoinSource
    MultiTenant.multi_tenant_model_for_table(arel.ast.relation.left.table_name)
  else
    MultiTenant.multi_tenant_model_for_table(arel.ast.relation.table_name)
  end
end

.multi_tenant_model_for_table(table_name) ⇒ Object



31
32
33
34
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 31

def self.multi_tenant_model_for_table(table_name)
  @@multi_tenant_models ||= {}
  @@multi_tenant_models[table_name.to_s]
end

.partition_key(tenant_name) ⇒ Object



8
9
10
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 8

def self.partition_key(tenant_name)
  "#{tenant_name.to_s}_id"
end

.query_monitor_enabled?Boolean

Returns:

  • (Boolean)


6
# File 'lib/activerecord-multi-tenant/query_monitor.rb', line 6

def self.query_monitor_enabled?; @@enable_query_monitor; end

.register_multi_tenant_model(table_name, model_klass) ⇒ Object

Registry that maps table names to models (used by the query rewriter)



27
28
29
30
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 27

def self.register_multi_tenant_model(table_name, model_klass)
  @@multi_tenant_models ||= {}
  @@multi_tenant_models[table_name.to_s] = model_klass
end

.tenant_klass_defined?(tenant_name) ⇒ Boolean

Returns:

  • (Boolean)


4
5
6
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 4

def self.tenant_klass_defined?(tenant_name)
  !!tenant_name.to_s.classify.safe_constantize
end

.with(tenant, &block) ⇒ Object



76
77
78
79
80
81
82
83
84
85
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 76

def self.with(tenant, &block)
  return block.call if self.current_tenant == tenant
  old_tenant = self.current_tenant
  begin
    self.current_tenant = tenant
    return block.call
  ensure
    self.current_tenant = old_tenant
  end
end

.with_lock_workaround_enabled?Boolean

Returns:

  • (Boolean)


24
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 24

def self.with_lock_workaround_enabled?; @@enable_with_lock_workaround; end

.with_write_only_mode_enabled?Boolean

Returns:

  • (Boolean)


19
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 19

def self.with_write_only_mode_enabled?; @@enable_write_only_mode ||= false; end

.without(&block) ⇒ Object



87
88
89
90
91
92
93
94
95
96
# File 'lib/activerecord-multi-tenant/multi_tenant.rb', line 87

def self.without(&block)
  return block.call if self.current_tenant.nil?
  old_tenant = self.current_tenant
  begin
    self.current_tenant = nil
    return block.call
  ensure
    self.current_tenant = old_tenant
  end
end