PicoJournal – Das Menü funktioniert und ist ausgelagert

Ich will das Menü auslagern und bei der Recherche stoße ich auf drei verschiedene Möglichkeiten, die alle irgendwie gleich sind. Deswegen will ich heute erst rausfinden, was für ein Menü am besten geeignet ist und das dann implementieren. Bonus: Bugfixes!

pfeildings

Hauptthema war heute das Auslagern des Menüs in eine einzelne Datei, damit ich das Monstrum nicht in jeder Datei für jede Unterseite haben muss und bei einer Änderung 12 Dateien aufrufen muss. In Rails kann man das HTML wegen der .erb Endung (Embedded Ruby) mit allerlei nützlichen Erweiterungen ausstatten. Eine wichtige Möglichkeit ist das Auslagern und wieder Einbinden von sich ansonsten wiederholendem Code.  Dazu existiert grundsätzlich erst einmal eine Default Layout Datei. Diese enthält normalerweise den head und die Verlinkungen auf CSS und Javascript. Also alles, was man auf wirklich jeder Unterseite braucht. Die wichtigste Zeile dieser Datei enthält den Befehl <%= yield %>. An der Stelle wo das geschrieben steht, werden alle Seiten reingeladen und vom Layout umschlossen. Den yield-Befehl kann man auch noch spezifizieren, wodurch ich diesen Befehl auch für das Menü nutzen könnte. Und wofür ist dann render? Die Quellen, die ich gefunden habe widersprechen sich teils, deswegen halte ich mich an die offizielle Seite. Zuerst einmal ist yield ein Ruby Befehl und render ein Rails Befehl. Der Guide verliert nicht allzu viele Worte zu dem Thema, doch die Konvention scheint zu sein, yield nur zu benutzen um die Seiten in das Layout zu bekommen. Da das Menü jedoch nur auf manchen Seiten auftaucht, passt es nicht in das Layout und es ist auch keine eigene Seite zum Einbinden. Somit ist render wohl besser geeignet. Hier also die konkrete Umsetzung:

 

Menü mit render auslagern

Zuerst kopiere ich das gesamte Menü von <nav> bis </nav> in eine neue Datei und speichere diese in einem neuen Ordner unter views/partials/navigation.html.erb .

Dann lösche ich in allen Seiten das Menü und ersetze es durch:

<!-- navigation -->
<%= render "partials/navigation" %>

Es taucht jedoch ein Fehler auf, da das Aufrufen dieses Befehls automatisch nach der Datei _navigation.html.erb sucht. Warum der Unterstrich? Rails Magie. Es ist eine aufgezwungene Konvention um Partials zu unterscheiden. Ich ändere also den Dateinamen in _navigation.html.erb und es funktioniert! Nun kann ich das Menü an einer einzigen Stelle manipulieren und es wird überall geändert. 

Aktiven Menüpunkt zeigen

Nun möchte ich noch, dass die aktuelle Seite im Menü hervorgehoben wird. Ich denke zuerst, dass ich dafür beim rendern eine Variable mit übergebe, doch eine kurze Google Suche liefert eine bessere Lösung. In der Datei helpers/application_helper.rb füge ich eine neue Funktion hinzu:

module ApplicationHelper
  #helps to show current menu item
  def cp(path)
    current_route = Rails.application.routes.recognize_path(path)
    "active" if current_page?(path)
  end
end

Diese Funktion gibt also den String acitve zurück, wenn der Funktionsparameter dem Seitenpfad entspricht. Jetzt muss ich nur noch die Links in der Navigation anpassen, sodass dieser String als Klasse hinzugefügt wird:

<ul class="nav navbar-nav">
        <li>
          <%= link_to 'Home', home_url, class: cp('/home') %>
        </li>
        <li>
          <%= link_to 'Days', days_url, class: cp('/days')  %>
        </li>
        <li>
          <%= link_to 'Stats', stats_url, class: cp('/stats')  %>
        </li>
        <li>
          <%= link_to 'About', about_url, class: cp('/about')  %>
        </li>
</ul>

Es funktioniert! Der jeweilige Menüpunkt wird farbig hervorgehoben.

Bonus Round: Verschwindende Styles bei Refresh

Bei einigen Seiten verschwanden die Styles, wenn man auf F5 gedrückt hat. Das hatte eindeutig irgendetwas mit dem Layout zu tun, ich hatte aber keine Ahnung was. Hier habe ich etwas falsch kopiert. Wenn man sich die Datei application_controller.rb ansieht erkennt man, dass dieser von ActionController::Base erbt. Das habe ich für meinen eigenen Controller einfach kopiert, doch das ist falsch. Die anderen Controller erben nämlich alle von ApplicationController. Ich musste also im von mir erstellten pages_controller.rb nur folgendes ändern:

# falsch
class PagesController < ActionController::Base
#richtig
class PagesController < ApplicationController

Awwwwwwwwwwwwwwwwwww yeah, es funktioniert wie gewollt.

pfeildings

Hier noch ein Screenshot der Ergebnisses, auch wenn man nicht allzu viel sehen kann.

Link zur Live Version

picojournal_menu

pfeildings

Das war es für heute. Nächste Woche beschäftige ich mit Devise und versuche den Usernamen mit in den Login einzubauen. Bis denne 🙂

*baut WordPress Theme*