iToverDose/Software· 1 JUNI 2026 · 16:05

Rails-7+-tauglicher Tenantify-Gem für sichere Multi-Tenancy-Lösungen

Wie der neue Ruby-Gem rails-tenantify Zeile-für-Zeile-Mehrmandantenfähigkeit für Rails-Apps bietet – ohne Schema-Overhead, mit Sidekiq-Integration und automatischer Abfragensicherung. Ideal für B2B-SaaS mit PostgreSQL.

DEV Community4 min0 Kommentare

*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 niemand unscoped nutzt.

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
end

Mandantenkontext 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
end

Alternativ 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?
end

Automatische 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_id

Sicheres 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
end

Direkter 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_tenant

Hintergrundjobs: 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
end

Installation in drei Schritten

  1. Gemfile aktualisieren:
gem "rails-tenantify", "~> 0.1.2", require: "rails-tenantify"
  1. 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
  1. Fremdschlüssel hinzufügen:

Für den Mandanten (z. B. organization_id) muss eine Migration erstellt werden:

add_reference :projects, :organization, foreign_key: true

Fazit: 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.

Kommentare

00
KOMMENTAR SCHREIBEN
ID #IVQ8XM

0 / 1200 ZEICHEN

Menschen-Check

4 + 9 = ?

Erscheint nach redaktioneller Prüfung

Moderation · Spam-Schutz aktiv

Noch keine Kommentare. Sei der erste.