Rails Anti-Patterns in Modellen – und wie man sie behebt

Rails fördert eine saubere Trennung von Belangen (Separation of Concerns), aber es ist leicht, Logik in die falsche Schicht durchsickern zu lassen. Das Modell soll Geschäftsregeln und Domänenverhalten kapseln, dennoch enden viele Anwendungen mit überladenen Controllern, aufgeblähten Ansichten (Views) oder übermäßig komplexen Modellen. Nachfolgend finden Sie gängige Anti-Patterns in Rails-Modellen und deren Lösungen mit Codebeispielen.


1. Ansichtslogik (View Logic) gehört in das Modell

Ein häufiger Fehler besteht darin, bedingte Geschäftslogik direkt in die Views einzufügen.

Schlecht:

<% if @order.total > 100 %>
  <p>Premium-Bestellung</p>
<% end %>

Besser: Verschieben Sie die Regel in das Modell.

class Order < ApplicationRecord
  def premium?
    total > 100
  end
end
<% if @order.premium? %>
  <p>Premium-Bestellung</p>
<% end %>

2. Callbacks, die zu viel tun

Callbacks sind nützlich, aber ihr übermäßiger Einsatz verbirgt wichtiges Verhalten.

Schlecht:

class User < ApplicationRecord
  after_create :send_welcome_email

  def send_welcome_email
    Mailer.welcome(self).deliver_now
  end
end

Besser: Extraktion in ein Service-Objekt.

class UserSignup
  def self.call(user)
    Mailer.welcome(user).deliver_now
  end
end
user = User.create!(params)
UserSignup.call(user)

3. SQL in Controllern

Anfragelogik verstopft Controller und streut Geschäftsregeln.

Schlecht:

@active_users = User.where("last_login > ?", 30.days.ago)

Besser: Verwenden Sie einen Scope im Modell.

class User < ApplicationRecord
  scope :recently_active, -> { where("last_login > ?", 30.days.ago) }
end
@active_users = User.recently_active

4. Serialisierte Attribute anstelle von Tabellen

Das Entleeren von Hashes in [serialize](https://api.rubyonrails.org/classes/ActiveModel/Serialization.html)-Spalten erschwert das Abfragen.

Schlecht:

class User < ApplicationRecord
  serialize :preferences, Hash
end

Besser: Normalisierung mit einer Erweiterung (Association).

class Preference < ApplicationRecord
  belongs_to :user
end

class User < ApplicationRecord
  has_many :preferences
end

5. Missbrauch der Single Table Inheritance (STI)

STI zwingt voneinander unabhängige Unterklassen in eine Tabelle, oft mit vielen NULL-Spalten.

Schlecht:

class Payment < ApplicationRecord; end
class CreditCardPayment < Payment; end
class BankTransferPayment < Payment; end

Besser: Verwenden Sie Polymorphismus oder Komposition.

class Payment < ApplicationRecord
  belongs_to :payable, polymorphic: true
end

class CreditCard < ApplicationRecord
  has_many :payments, as: :payable
end

Dieser Beitrag wurde von dem Buch Rails AntiPatterns: Best Practice Ruby on Rails Refactoring von Chad Pytel und Tammer Saleh inspiriert. Wenn Sie das gesamte Buch lesen möchten, finden Sie es auf Amazon: Rails AntiPatterns

Wenn Sie das Buch über diesen Amazon-Link kaufen, kann ich eine kleine Provision ohne zusätzliche Kosten für Sie verdienen — danke für die Unterstützung dieses Inhalts.


Wichtigste Erkenntnisse

  • Verschieben Sie Geschäftsregeln in Modelle (nicht in Views oder Controller).
  • Verwenden Sie Service-Objekte, wenn Callbacks zu viel verstecken.
  • Halten Sie SQL in Scopes, vermeiden Sie verstreute Anfragen.
  • Normalisieren Sie Datenstrukturen, vermeiden Sie serialisierte Blobs.
  • Vermeiden Sie den Missbrauch von STI; bevorzugen Sie polymorphes oder kompositorisches Design.

Durch das Refactoring dieser Anti-Patterns bleiben Ihre Modelle ausdrucksstark, Ihre Controller schlank und Ihre Views sauber.