Tenancy Reference
Three closely-coupled concerns:
- Entity scoping — every record belongs to a tenant; queries filter automatically.
- Nested resources — parent/child URLs; parent scoping takes precedence over entity scoping.
- Invites — onboarding users into a tenant's membership.
How entity scoping fits together
Three cooperating pieces:
| Piece | Role |
|---|---|
| Portal | Declares the entity class and how to resolve it from the request (scope_to_entity Organization, strategy: :path). |
| Policy | default_relation_scope(relation) calls relation.associated_with(entity_scope) on every collection query. Enforced via verify_default_relation_scope_applied!. |
| Model | associated_with(entity) resolves via custom scope, direct association, or has_one :through. |
Configure the portal once. The policy and model conventions then carry tenancy automatically.
🚨 Critical (applies to all three sub-pages)
- Never bypass
default_relation_scope. Overridingrelation_scopewithwhere(organization: ...)or manual joins triggersverify_default_relation_scope_applied!. Always calldefault_relation_scope(relation)explicitly — notsuper. - Always declare an association path from the model to the entity. Direct
belongs_to,has_one :through, or a customassociated_with_<entity>scope. Ifassociated_withcan't resolve, fix the model, not the policy. - Parent scoping beats entity scoping. When a parent is present (nested resource),
default_relation_scopescopes via the parent, not viaentity_scope. Don't double-scope. - One level of nesting only. Grandparent → parent → child nested routes are NOT supported. Use top-level routes for deeper relationships.
- Compound uniqueness scoped to the tenant FK.
validates :code, uniqueness: {scope: :organization_id}— without this, uniqueness leaks across tenants. - Invite email must match the accepting user's email. Security feature — don't disable
enforce_email?lightly.
Related
- Behavior › Policy —
relation_scopesyntax - Resource › Model — model layer (associations,
has_cents, SGID) - App › Portals —
scope_to_entityengine config - Guides › Multi-tenancy — task-oriented walkthrough
- Guides › User invites — invitation setup recipe
