Eine nette, mir bisher unbekannte Methode ist Rubys Object#tap, der man einen Block übergeben kann, in dem das Objekt als Argument zur Verfügung steht. Klingt im ersten Moment vielleicht unnötig, kann aber insbesondere in Views für etwas schöneren Code sorgen. Ein kleines Negativbeispiel in HAML:
%table %tbody %tr %td= current_company.name %td= current_company.owner ? "#{current_company.owner.first_name} #{current_company.owner.last_name}" : t('.unknown_owner')
Object#tap
Die ständige Wiederholung von current_company.owner
streckt den Code. Gäbe es mehrere Besitzer, würde ein current_company.owners.each do |owner|
Abhilfe schaffen und den Zugriff owner
im folgenden Block bereitstellen. Tap macht genau das selbe, nur dass es auf jedem Objekt, also auch Nicht-Kollektionen funktioniert:
%table %tbody %tr %td= current_company.name - current_company.owner.tap do |owner| %td= owner ? "#{owner.first_name} #{owner.last_name}" : t('.unknown_owner')
Eine gute Zeile im Sinne der Lesbarkeit.
Information Hiding
Genau genommen ist es Glück, dass die Code-Stelle selbst mit dieser Änderung etwas unsauber aussieht. Sie zeigt uns ein Problem mit der Datenkapselung. Ein View für ein Unternehmen sollte nicht wissen müssen, aus welchen Details sich ein Darstellungsname des Besitzers ergibt. Hierfür bietet Rails die (an dieser Stelle etwas zu umständlichen) Partials oder Helper: display_owner(owner)
.
Decorators: Draper und Co.
Nun sind Helper für den objektorientierten Entwickler eine hässliche Sache, da sie auf Modulen basieren und nur eine Sammlung view-globaler Methoden darstellen. Einen besseren Ansatz bieten Decorators, die es für Rails etwa in Form von Draper gibt. Ist ein Owner dekoriert, ruft man im View z.B. owner.display_name
oder gar owner
auf. Für letzteres muss lediglich die Methode to_s
des Dekorators überschrieben werden:
class OwnerDecorator < Draper::Decorator decorates :owner delegate_all include Draper::LazyHelpers def to_s if owner link_to "#{first_name} #{last_name}", owner_path(owner) else "" end end end
Somit lässt sich an jeder Stelle denkbar einfach ein nullsicherer Link zu einem Besitzer einbinden. Auch Rechteverwaltung kann an dieser Stelle eingebracht werden, da der Dekorator Zugriff auf alle Helper und den Controller hat. Zudem lässt sich das ganze noch isoliert testen.
Sind die Dekoratoren korrekt konfiguriert, sieht das eingangs vorgestellte Problem nicht mehr wie eines aus:
%table %tbody %tr %td= current_company.name %td= current_company.owner