docs/developer/multi-tenant/core-concepts.mdx
The center of the multi-tenant architecture is the Spree::Tenant class. This is the highest level class in the multi-tenant system.
Every tenanted model includes a tenant_id column. This is used to identify which tenant a record belongs to. It's row-level multi-tenancy.
After creating a new tenant it will automatically create store and run Spree seeds to populate data such as countries, zones, tax rates, etc.
All models that are tenanted inherit from SpreeMultiTenant::Base class. spree_multi_tenant automatically sets the Spree.base_class to SpreeMultiTenant::Base so all standard Spree models will be tenanted (with an exclusion of Spree::CustomDomain).
When creating a new model that you want to be tenanted remember to inherit from SpreeMultiTenant::Base and not from Spree::Base and add tenant_id column to the table, eg.
bin/rails g model Spree::NewModel tenant:references name:string --parent SpreeMultiTenant::Base
By default the current tenant is selected based on the subdomain or Spree::CustomDomain. The selector works in tandem with the default Spree::Stores::FindCurrent finder.
First it finds the current store, and later sets the current tenant based on the store's tenant_id.
Tenant record is accessible in views and controllers as current_tenant. In models you can access it via SpreeMultiTenant.current_tenant.
All code run when SpreeMultiTenant.current_tenant is set will be executed in the context of the tenant, what that means:
tenant_id = <current_tenant.id> to the querytenant_id to the current tenant ID (you don't need to do it manually)Background jobs enqueued when SpreeMultiTenant.current_tenant is set will be executed in the context of the tenant.
Sometimes when you're not sure if the tenant context is active you can use SpreeMultiTenant.with_tenant to enforce it, eg.
SpreeMultiTenant.with_tenant(tenant) do
# all operations here will be executed in the context of the tenant
end
Sometimes you want to run a piece of code outside of the tenant context, for that you can use SpreeMultiTenant.without_tenant
SpreeMultiTenant.without_tenant do
# all operations here will be executed outside of the tenant context
end
When using bin/rails console or bin/rails runner you can set the tenant context by:
SpreeMultiTenant.current_tenant = Spree::Store.find_by(code: 'my_store').tenant