*Moderne SaaS-Anwendungen müssen Daten streng nach Mandanten trennen – doch klassische Lösungen wie acts_as_tenant oder Apartment bringen heute oft mehr Probleme als Vorteile.*
Der neue Open-Source-Gem rails-tenantify ändert das: Er setzt auf Zeilenebene-tenancy mit PostgreSQL, vermeidet Schema-Komplexität und erhält den Mandantenkontext sogar in Hintergrundjobs. Entwickler sparen sich manuelle default_scope-Implementierungen und riskante unscoped-Aufrufe.
Warum Zeilenebene-Tenancy die bessere Wahl ist
Jede Multi-Tenant-SaaS-App steht vor denselben Herausforderungen:
- Wie verhindert man, dass Mandant A Daten von Mandant B einsehen kann?
- Wie stellt man sicher, dass jede Abfrage automatisch auf den richtigen Mandanten gefiltert wird?
- Wie bleibt der Mandantenkontext in Sidekiq-Jobs oder Wiederholungsversuchen erhalten?
- Wie schützt man vor versehentlichen
update_all-Befehlen, die alle Datensätze aller Mandanten löschen?
Bisherige Antworten wie acts_as_tenant oder Apartment bringen eigene Probleme mit:
- Ungewarteter Code: Viele Gems sind nicht für Rails 7+ optimiert und führen zu API-Konflikten.
- Verlorener Kontext: Hintergrundjobs verlieren den Mandantenbezug bei Wiederholungen.
- Schema-Per-Tenant: Apartment erfordert separate Datenbank-Schemata – mit hohem DevOps-Aufwand.
- Eigene Implementierungen: Teams schreiben oft eigene
default_scope-Logik und hoffen, dass niemandunscopednutzt.
rails-tenantify setzt stattdessen auf eine einfache, aber sichere Zeilenebene-Tenancy: Eine Datenbank, eine Spalte wie organization_id und strikte Filterung aller Abfragen.
Die Kernfunktionen im Überblick
Der Gem integriert sich nahtlos in Rails-Modelle und Controller. Nach der Installation reicht ein einziger Include-Befehl, um die Tenancy-Logik zu aktivieren:
class Project < ApplicationRecord
include Tenantify::Scoped
belongs_to_tenant :organization
endMandantenkontext pro Request festlegen
Im Controller wird der aktuelle Mandant einmalig pro Anfrage gesetzt – etwa über die Subdomain:
class ApplicationController < ActionController::Base
set_tenant_by :subdomain # Beispiel: acme.deineapp.com → Organization
endAlternativ lässt sich der Mandant über API-Header oder die Session auflösen:
# Header-basierte Auflösung für mobile Clients
set_tenant_by :header, header: "X-Tenant-ID"
# Manuelle Auflösung in der Session
before_action do
Tenantify.current_tenant = current_user.organization if user_signed_in?
endAutomatische Abfragensicherung
Jede Datenbankabfrage wird nun automatisch auf den aktuellen Mandanten gefiltert:
Tenantify.current_tenant = current_organization
Project.all # Gibt nur Projekte des aktuellen Mandanten zurück
Project.create!(name: "Roadmap") # Setzt automatisch organization_idSicheres Umschalten des Mandantenkontexts
Für Admin-Skripte oder Wartungsaufgaben kann der Kontext temporär gewechselt werden:
# Temporärer Wechsel
Tenantify.switch_to(other_org) do
Project.count # Wird für other_org gezählt
end
# Explizites Umgehen der Tenancy (nur für spezielle Fälle)
Tenantify.without_tenant do
Project.delete_all # Wirft Tenantify::TenantMismatchError
endDirekter Vergleich: rails-tenantify vs. etablierte Lösungen
Der Gem wurde von Grund auf für Rails 7+ entwickelt und adressiert typische Schmerzpunkte älterer Ansätze:
| Funktion | acts_as_tenant | rails-tenantify | |----------|---------------------|---------------------| | Rails 7+ Kompatibilität | Teilweise | Vollständig | | Subdomain-Auflösung | Manuelle Implementierung | set_tenant_by :subdomain | | Header-Auflösung | Manuelle Implementierung | set_tenant_by :header | | Sidekiq-Integration | Bekannte Probleme bei Wiederholungen | Mandanten-ID wird automatisch im Job gespeichert | | Schutz vor bulk-Writes | Unzuverlässig | Wirft Fehler, außer bei expliziter Freigabe | | Kreuz-Mandanten-Assoziationen | Manuelle Prüfung | Automatische Validierung | | Riskante Tenant-Wechsel | Keine Warnung | Optionale Prüfung (:log, :raise, :ignore) | | Test-Hilfsmittel | Teilweise | Native Helfer wie with_tenant |
Gegenüber Apartment setzt rails-tenantify auf eine schlankere Architektur mit nur einer Datenbank:
| Funktion | Apartment | rails-tenantify | |----------|--------------|---------------------| | Isolationsmodell | Separate Schemata/Datenbanken | Zeilenebene mit Fremdschlüssel | | Migrationen | Komplexität pro Mandant | Standard-Rails-Migrationen | | Operations-Aufwand | Hoch | Gering | | Einsatzszenario | Hohe Compliance-Anforderungen | Typische B2B-SaaS-Anwendungen |
Bulk-Writes sicher machen: Der gefährlichste Tenancy-Fußangel
Ein versehentlicher Project.update_all(status: "archived") ohne Mandantenfilter kann alle Daten aller Mandanten überschreiben. rails-tenantify schützt davor:
Project.update_all(status: "archived")
# Wirft Tenantify::TenantMismatchError
Project.unscoped.update_all(status: "migrated")
# Funktioniert nur mit explizitem Tenantify.without_tenantHintergrundjobs: Mandantenkontext erhalten
Der Gem stellt sicher, dass der Mandant auch in Hintergrundjobs – ob mit ActiveJob oder Sidekiq – erhalten bleibt:
class ExportJob < ApplicationJob
def perform
Tenantify.current_tenant # Wird automatisch auf den Mandanten gesetzt, der den Job enqueued hat
Project.find_each { |p| p.update!(exported: true) }
end
endInstallation in drei Schritten
- Gemfile aktualisieren:
gem "rails-tenantify", "~> 0.1.2", require: "rails-tenantify"- Initializer erstellen (
config/initializers/tenantify.rb):
Tenantify.configure do |config|
config.tenant_model = "Organization" # Name des Mandanten-Modells
config.on_tenant_not_found = :raise # Optionen: :raise | :redirect | :null_tenant
config.audit_overrides = :log # Optionen: :log | :raise | :ignore
end- Fremdschlüssel hinzufügen:
Für den Mandanten (z. B. organization_id) muss eine Migration erstellt werden:
add_reference :projects, :organization, foreign_key: trueFazit: Die Zukunft der Rails-Tenancy
rails-tenantify kombiniert die Einfachheit der Zeilenebene-Tenancy mit moderner Rails-7+-Kompatibilität – ohne externe Abhängigkeiten oder komplexe DevOps-Prozesse.
Für B2B-SaaS-Produkte, die eine robuste, wartbare und sichere Datenisolierung benötigen, ist der Gem eine überzeugende Alternative zu veralteten oder überkomplexen Lösungen.
Mit integriertem Schutz vor bulk-Writes, Sidekiq-Kompatibilität und klaren Fehlermeldungen wird er zu einem unverzichtbaren Werkzeug für Rails-Entwickler, die sich auf ihre Anwendung konzentrieren wollen – statt auf Tenancy-Bugs.
Die Zukunft der Rails-Tenancy ist zeilenbasiert. Und mit rails-tenantify ist sie endlich einfach umzusetzen.
KI-Zusammenfassung
Rails 7+ projelerinizde çoklu kiracılı sistemleri güvenle uygulamak için rails-tenantify gem'ini keşfedin. Satır düzeyinde kiracı izolasyonu, arka plan görevlerinde güvenlik ve toplu işlem koruması sunuyor.