Class: RailsOnboarding::MultiTenant

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_onboarding/multi_tenant.rb

Overview

Multi-Tenant Support Allows different onboarding configurations per organization/tenant

Class Method Summary collapse

Class Method Details

.clear_all_configurationsObject

Clear all organization configurations (useful for testing)



30
31
32
33
# File 'lib/rails_onboarding/multi_tenant.rb', line 30

def clear_all_configurations
  @organization_configurations = {}
  @merged_configuration_cache = {}
end

.configuration_for(tenant) ⇒ Hash

Get configuration for a specific tenant

Parameters:

  • tenant (Object, Integer, String)

    The tenant object or organization ID

Returns:

  • (Hash)

    Tenant-specific configuration



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rails_onboarding/multi_tenant.rb', line 39

def configuration_for(tenant)
  return default_configuration unless tenant

  # Check if tenant is an ID (for organization_configurations lookup)
  if tenant.is_a?(Integer) || tenant.is_a?(String)
    return merged_configuration_cache[tenant] ||= begin
      stored_config = organization_configurations[tenant]
      stored_config ? merge_configurations(default_configuration, stored_config) : default_configuration
    end
  end

  # Check if tenant has custom configuration
  tenant_config = if tenant.respond_to?(:onboarding_configuration)
                    tenant.onboarding_configuration
  elsif tenant.respond_to?(:onboarding_config)
                    tenant.onboarding_config
  end

  return default_configuration unless tenant_config

  # Merge with default configuration
  merge_configurations(default_configuration, parse_config(tenant_config))
end

.configure_for_organization(organization_id) {|config| ... } ⇒ Object

Configure onboarding for a specific organization by ID

Parameters:

  • organization_id (Integer, String)

    The organization ID

Yields:

  • (config)

    Configuration object to customize



22
23
24
25
26
27
# File 'lib/rails_onboarding/multi_tenant.rb', line 22

def configure_for_organization(organization_id)
  config = OrganizationConfig.new(organization_id)
  yield config if block_given?
  organization_configurations[organization_id] = config.to_hash
  merged_configuration_cache.delete(organization_id)
end

.copy_configuration(source_tenant, target_tenant) ⇒ Object

Copy configuration from one tenant to another

Parameters:

  • source_tenant (Object)

    Source tenant

  • target_tenant (Object)

    Target tenant



192
193
194
195
# File 'lib/rails_onboarding/multi_tenant.rb', line 192

def copy_configuration(source_tenant, target_tenant)
  config = configuration_for(source_tenant)
  set_configuration(target_tenant, config)
end

.feature_enabled?(tenant, feature) ⇒ Boolean

Check if a feature is enabled for a tenant

Parameters:

  • tenant (Object)

    The tenant object

  • feature (Symbol)

    The feature to check

Returns:

  • (Boolean)

    True if feature is enabled



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/rails_onboarding/multi_tenant.rb', line 95

def feature_enabled?(tenant, feature)
  config = configuration_for(tenant)

  case feature
  when :tooltips
    config[:enable_tooltips] != false
  when :milestones
    config[:enable_milestones] != false
  when :analytics
    config[:enable_analytics] != false
  when :ab_testing
    config[:enable_ab_testing] == true
  when :personalization
    config[:personalization_enabled] == true
  else
    false
  end
end

.merged_configuration_cacheObject

Merged configuration is cached per organization ID so repeated lookups (every onboarding request) don't re-merge the same hash every time. Invalidated whenever that organization is reconfigured or cleared.



14
15
16
# File 'lib/rails_onboarding/multi_tenant.rb', line 14

def merged_configuration_cache
  @merged_configuration_cache ||= {}
end

.milestones_for(tenant) ⇒ Array<Hash>

Get milestones for a specific tenant

Parameters:

  • tenant (Object)

    The tenant object

Returns:

  • (Array<Hash>)

    Milestone configurations



85
86
87
88
# File 'lib/rails_onboarding/multi_tenant.rb', line 85

def milestones_for(tenant)
  config = configuration_for(tenant)
  config[:milestones] || RailsOnboarding.configuration.milestones
end

.organization_configurationsObject

Storage for organization-specific configurations (by ID)



7
8
9
# File 'lib/rails_onboarding/multi_tenant.rb', line 7

def organization_configurations
  @organization_configurations ||= {}
end

.organization_for_user(user) ⇒ Integer, ...

Get organization ID for user

Parameters:

  • user (User)

    The user object

Returns:

  • (Integer, String, nil)

    The organization ID



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/rails_onboarding/multi_tenant.rb', line 139

def organization_for_user(user)
  return nil unless user

  # Try to get organization_id directly
  if user.respond_to?(:organization_id)
    return user.organization_id
  end

  # Otherwise, get tenant and extract its ID
  tenant = tenant_from_user(user)
  tenant&.id
end

.reset_configuration(tenant) ⇒ Object

Reset tenant configuration to default

Parameters:

  • tenant (Object)

    The tenant object



200
201
202
203
204
205
206
207
# File 'lib/rails_onboarding/multi_tenant.rb', line 200

def reset_configuration(tenant)
  return unless tenant

  if tenant.respond_to?(:onboarding_configuration=)
    tenant.onboarding_configuration = nil
    tenant.save
  end
end

.set_configuration(tenant, config) ⇒ Object

Set custom configuration for a tenant

Parameters:

  • tenant (Object)

    The tenant object

  • config (Hash)

    Configuration hash



177
178
179
180
181
182
183
184
185
186
# File 'lib/rails_onboarding/multi_tenant.rb', line 177

def set_configuration(tenant, config)
  return unless tenant

  if tenant.respond_to?(:onboarding_configuration=)
    tenant.onboarding_configuration = config.to_json
    tenant.save
  elsif tenant.respond_to?(:update)
    tenant.update(onboarding_configuration: config.to_json) rescue nil
  end
end

.steps_for(tenant) ⇒ Array<Hash>

Get steps for a specific tenant

Parameters:

  • tenant (Object)

    The tenant object

Returns:

  • (Array<Hash>)

    Array of step configurations



67
68
69
70
# File 'lib/rails_onboarding/multi_tenant.rb', line 67

def steps_for(tenant)
  config = configuration_for(tenant)
  config[:steps] || RailsOnboarding.configuration.steps
end

.tenant_from_user(user) ⇒ Object?

Get tenant from user

Parameters:

  • user (User)

    The user object

Returns:

  • (Object, nil)

    The tenant object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rails_onboarding/multi_tenant.rb', line 156

def tenant_from_user(user)
  return nil unless user

  # Try common tenant associations
  if user.respond_to?(:organization)
    user.organization
  elsif user.respond_to?(:account)
    user.
  elsif user.respond_to?(:tenant)
    user.tenant
  elsif user.respond_to?(:team)
    user.team
  elsif user.respond_to?(:company)
    user.company
  end
end

.tooltips_for(tenant) ⇒ Hash

Get feature tooltips for a specific tenant

Parameters:

  • tenant (Object)

    The tenant object

Returns:

  • (Hash)

    Feature tooltip configurations



76
77
78
79
# File 'lib/rails_onboarding/multi_tenant.rb', line 76

def tooltips_for(tenant)
  config = configuration_for(tenant)
  config[:feature_tooltips] || RailsOnboarding.configuration.feature_tooltips
end

.with_tenant_configuration(tenant) { ... } ⇒ Object

Apply tenant configuration to current context, for the duration of the block only. This does NOT touch RailsOnboarding.configuration itself - it sets a thread/fiber-local override (RailsOnboarding::Current) that Configuration's readers consult first, so concurrent requests for other tenants (or no tenant) are never affected, and everything is automatically cleared even if this method's own ensure never ran (Rails resets CurrentAttributes around every request and job).

Parameters:

  • tenant (Object)

    The tenant object

Yields:

  • Block to execute with tenant configuration



124
125
126
127
128
129
130
131
132
133
# File 'lib/rails_onboarding/multi_tenant.rb', line 124

def with_tenant_configuration(tenant)
  return yield unless tenant

  previous_overrides = RailsOnboarding::Current.tenant_overrides
  RailsOnboarding::Current.tenant_overrides = tenant_config_overrides(tenant)

  yield
ensure
  RailsOnboarding::Current.tenant_overrides = previous_overrides
end