Darstellung
Navigation
Mobiles Menü
Darstellung
Navigation
Mobiles Menü
Basis-Code

Basis-Code

Ein kurzes Tutorial zum Basis-Code den ich verwende.

Vorbereitung

Eine einfache Basis-App für unsere Tutorials erstellen

In vielen unserer Rails-Tutorials benötigen wir nur eine kleine Beispielanwendung, um eine bestimmte Funktion auszuprobieren. Damit diese Anwendungen nicht jedes Mal vollkommen ungestaltet aussehen, erstellen wir in diesem Tutorial eine einfache Basis, die wir später auch in anderen Projekten verwenden können.
Unsere Basis soll unter anderem einen übersichtlichen Inhaltsbereich, einfache Formularstyles, Validierungsfehler und Flash-Meldungen erhalten.
Zum Ausprobieren erstellen wir eine kleine Rails-Anwendung mit einer User-Ressource.
Zunächst erstellen wir die Anwendung:
$ rails new basic
$ cd basic
Anschließend erzeugen wir einen Scaffold für unsere Benutzer:
$ rails g scaffold User name:string email:string
Rails hätte bei diesen beiden Attributen auch ohne die explizite Angabe :string String-Spalten erzeugt. Wir schreiben den Typ hier trotzdem aus, damit bereits beim Generator-Aufruf eindeutig erkennbar ist, welche Datentypen wir verwenden.
Danach führen wir die Migration aus:
$ rails db:migrate
Nun starten wir die Anwendung:
$ bin/rails server
Anschließend können wir im Browser die Benutzerübersicht aufrufen:
/users
Über:
/users/new
erreichen wir das vom Scaffold erzeugte Formular zum Erstellen eines neuen Benutzers.
Damit besitzen wir eine vollständige kleine CRUD-Anwendung, die uns als Ausgangspunkt für die weitere Gestaltung dient.

Einen gemeinsamen Seitenbereich verwenden

Den Inhalt in einem Container darstellen

Bevor wir mit dem eigentlichen Styling beginnen, passen wir das Application-Layout an.
Rails verwendet:
app/views/layouts/application.html.erb
als gemeinsames Layout unserer Views.
Innerhalb des <body> legen wir einen main-Bereich mit der Klasse container an:
<!-- app/views/layouts/application.html.erb -->

<body>
  <main class="container">
    <%= yield %>
  </main>
</body>
yield ist die Stelle, an der Rails den Inhalt der jeweils aufgerufenen View einfügt.
Rufen wir beispielsweise:
/users
auf, wird die Benutzerübersicht innerhalb unseres main.container dargestellt.
Dasselbe gilt für:
/users/new
und die übrigen Views unserer Anwendung.
Wir müssen den Container deshalb nicht in jeder einzelnen View erneut anlegen.

Grundlegende Gestaltung

Die Basis-App mit CSS gestalten

Für unsere kleine Basis-App benötigen wir kein zusätzliches Sass-Gem. Das Styling, das wir verwenden möchten, lässt sich vollständig mit normalem CSS umsetzen.
Wir verwenden dafür das vorhandene Stylesheet:
app/assets/stylesheets/application.css
Am Ende der Datei ergänzen wir zunächst die grundlegende Gestaltung unserer Anwendung:
html,
body {
  margin: 0;
  min-height: 100%;
}

body {
  background-color: #c2e7ff;
  color: #222;
  font-family: Verdana, Helvetica, Arial, sans-serif;
  font-size: 14px;
}

a {
  color: #2e47d2;
}

a:visited {
  color: #2e47d2;
}

a:hover,
a:focus {
  color: #0000ff;
}

img {
  max-width: 100%;
  height: auto;
  border: 0;
}

.container {
  width: min(75%, 1100px);
  margin: 40px auto;
  padding: 20px 40px;
  box-sizing: border-box;

  background-color: #fff;
  border-radius: 24px;
  box-shadow: 0 0 5px rgba(1, 1, 1, 0.7);
}

@media (max-width: 700px) {
  .container {
    width: calc(100% - 24px);
    margin: 20px auto;
    padding: 20px;
    border-radius: 16px;
  }
}
Damit erhält die Anwendung einen hellblauen Hintergrund und der eigentliche Seiteninhalt erscheint in einem weißen Container.
Im Vergleich zu einer festen Breite bleibt der Container durch:
width: min(75%, 1100px);
auch auf großen Bildschirmen übersichtlich.
Für kleinere Displays passen wir den Container über eine Media Query an:
@media (max-width: 700px) {
  .container {
    width: calc(100% - 24px);
    margin: 20px auto;
    padding: 20px;
    border-radius: 16px;
  }
}
Dadurch bleibt unsere einfache Basis auch auf schmaleren Bildschirmen benutzbar.

Links etwas dezenter gestalten

Die vom Browser vorgegebenen Linkfarben unterscheiden sich je nach Zustand. Für unsere Basis verwenden wir deshalb ein einheitlicheres Erscheinungsbild:
a {
  color: #2e47d2;
}

a:visited {
  color: #2e47d2;
}

a:hover,
a:focus {
  color: #0000ff;
}
Wir setzen dabei bewusst keine weiße Hintergrundfarbe auf Links. Dadurch funktionieren Links auch außerhalb unseres weißen Containers, ohne einen unerwünschten weißen Hintergrund zu erhalten.

Formulare gestalten

Als Nächstes passen wir die vom Scaffold erzeugten Formulare an.
Wir ergänzen in application.css:
form {
  margin: 20px 0;
}

form > div {
  margin: 12px 0;
}

label {
  display: block;
  margin-bottom: 6px;
}

input,
textarea,
select {
  width: 100%;
  max-width: 600px;
  box-sizing: border-box;
  padding: 12px;

  font: inherit;

  border: 1px solid #aaa;
  border-radius: 6px;
  background-color: #fff;
}

textarea {
  min-height: 10rem;
  resize: vertical;
}

select {
  max-width: 400px;
}

input[type="checkbox"],
input[type="radio"] {
  width: auto;
}

input[type="submit"],
button {
  width: auto;
  min-width: 160px;
  padding: 10px 16px;

  font: inherit;
  cursor: pointer;
}
Durch:
box-sizing: border-box;
werden Padding und Rahmen in die angegebene Breite des Eingabefeldes eingerechnet. Dadurch können die Felder nicht allein durch ihr Padding breiter als vorgesehen werden.
Die maximale Breite:
max-width: 600px;
verhindert gleichzeitig, dass kurze Formulareingaben auf großen Bildschirmen unnötig über die gesamte Seite gezogen werden.
Checkboxen und Radio-Buttons sind eine Ausnahme. Sie sollen nicht die vollständige verfügbare Breite einnehmen:
input[type="checkbox"],
input[type="radio"] {
  width: auto;
}
Auch Submit-Buttons erhalten keine feste Breite. Stattdessen verwenden wir eine Mindestbreite:
input[type="submit"],
button {
  width: auto;
  min-width: 160px;
}
Dadurch kann ein Button automatisch breiter werden, wenn seine Beschriftung mehr Platz benötigt.
Unsere Benutzerformulare besitzen damit bereits eine einfache und wiederverwendbare Grundgestaltung.

Validierungsfehler anzeigen

Pflichtfelder für den User festlegen

Bis jetzt können wir einen Benutzer auch dann speichern, wenn weder ein Name noch eine E-Mail-Adresse eingegeben wurde.
Damit wir die Fehlerdarstellung unserer Basis-App ausprobieren können, legen wir deshalb fest, dass beide Felder ausgefüllt werden müssen.
Dazu ergänzen wir unser User-Model:
# app/models/user.rb

class User < ApplicationRecord
  validates :name, :email, presence: true
end
Mit:
validates :name, :email, presence: true
prüft Rails vor dem Speichern, ob für name und email ein Wert vorhanden ist.
Versuchen wir jetzt unter:
/users/new
einen Benutzer ohne Name und E-Mail-Adresse anzulegen, schlägt die Validierung fehl.
Rails speichert den Datensatz nicht und das Formular wird erneut mit den vorhandenen Validierungsfehlern angezeigt.
Bei zwei leeren Feldern erhalten wir beispielsweise die Meldungen:
Name can't be blank
Email can't be blank
Die Validierung gehört dabei in das Model und gilt damit unabhängig davon, über welches Formular oder welchen Controller der Datensatz gespeichert werden soll.
5.webp 49 KB



Die vom Scaffold erzeugte Fehlerausgabe

Der Rails-Scaffold erzeugt im Formular bereits eine Fehlerausgabe für fehlgeschlagene Validierungen.
In:
app/views/users/_form.html.erb
finden wir einen Bereich, der nur angezeigt wird, wenn der aktuelle User Fehler enthält.
Wir gestalten diesen Bereich für unsere Basis-App etwas übersichtlicher und verwenden dafür eine eigene CSS-Klasse.
Der Anfang unseres Formular-Partials sieht anschließend so aus:
<!-- app/views/users/_form.html.erb -->

<%= form_with(model: user) do |form| %>
  <% if user.errors.any? %>
    <div class="error-messages">
      <h2>
        <%= pluralize(user.errors.count, "error") %>
        prohibited this user from being saved:
      </h2>

      <ul>
        <% user.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <!-- Die übrigen Formularfelder bleiben unverändert. -->
<% end %>
Wichtig ist dabei:
<% if user.errors.any? %>
Die Fehlerbox wird also nur erzeugt, wenn tatsächlich Validierungsfehler vorhanden sind.
Mit:
<%= pluralize(user.errors.count, "error") %>
wird die Anzahl der vorhandenen Fehler ausgegeben.
Und:
<% user.errors.each do |error| %>
  <li><%= error.full_message %></li>
<% end %>
gibt die einzelnen Fehlermeldungen als Liste aus.

Die Fehlerbox gestalten

Nun ergänzen wir unser Stylesheet:
/* app/assets/stylesheets/application.css */

.error-messages {
  width: 100%;
  max-width: 500px;
  margin-bottom: 20px;

  border: 2px solid #c6281b;
  background-color: #f5f5f5;
}

.error-messages h2 {
  margin: 0;
  padding: 8px 12px;

  background-color: #c6281b;
  color: #fff;

  font-size: 14px;
  font-weight: bold;
}

.error-messages ul {
  margin: 12px 0;
  padding-left: 32px;
}

.error-messages li {
  margin: 5px 0;
}
Damit erhält die Fehlerausgabe einen roten Rahmen und eine deutlich hervorgehobene Überschrift.
Die eigentlichen Fehlermeldungen bleiben darunter gut lesbar auf einem neutralen Hintergrund.
Da wir:
width: 100%;
max-width: 500px;
verwenden, bleibt die Fehlerbox auf größeren Bildschirmen kompakt, kann sich auf kleineren Bildschirmen aber an den verfügbaren Platz anpassen.
Damit besitzen unsere Formulare eine einheitliche Darstellung für Validierungsfehler, die wir auch in anderen Formularen unserer Tutorials wiederverwenden können.
6.webp 42.6 KB

Flash-Meldungen zentral anzeigen

Erfolgs- und Fehlermeldungen im Layout ausgeben

Nach bestimmten Aktionen verwendet Rails Flash-Meldungen, um dem Benutzer eine Rückmeldung zu geben.
Nach dem erfolgreichen Erstellen eines Users setzt der vom Scaffold erzeugte Controller beispielsweise eine Meldung wie:
User was successfully created.
Nach dem Löschen eines Users erhalten wir entsprechend:
User was successfully destroyed.
Der Scaffold gibt solche Meldungen zunächst direkt in einzelnen Views aus. In app/views/users/index.html.erb und app/views/users/show.html.erb kann sich beispielsweise folgende Zeile befinden:
<p style="color: green"><%= notice %></p>
Diese Ausgabe entfernen wir aus den einzelnen Views.
Statt Flash-Meldungen auf jeder Seite separat auszugeben, platzieren wir die Ausgabe einmal zentral in unserem Application-Layout.
Dazu ergänzen wir innerhalb unseres Containers und vor <%= yield %>:
<!-- app/views/layouts/application.html.erb -->

<body>
  <main class="container">
    <% flash.each do |type, message| %>
      <div class="flash-message flash-<%= type %>">
        <%= message %>
      </div>
    <% end %>

    <%= yield %>
  </main>
</body>
Durch:
<% flash.each do |type, message| %>
durchlaufen wir alle für den aktuellen Request vorhandenen Flash-Meldungen.
Der eigentliche Text befindet sich in:
<%= message %>
Zusätzlich verwenden wir zwei CSS-Klassen.
Jede Flash-Meldung erhält:
flash-message
und abhängig von ihrem Typ beispielsweise:
flash-notice
oder:
flash-alert
Dadurch können wir die allgemeine Gestaltung und die verschiedenen Meldungstypen getrennt definieren.

Flash-Meldungen gestalten

In unserem Stylesheet ergänzen wir:
/* app/assets/stylesheets/application.css */

.flash-message {
  margin-bottom: 20px;
  padding: 10px 12px;

  border: 1px solid;
  border-radius: 4px;
}

.flash-notice {
  color: #1f5f1f;
  background-color: #d9f7d9;
  border-color: #6c6;
}

.flash-alert {
  color: #8a1f1f;
  background-color: #fdd;
  border-color: #c66;
}
Eine normale Erfolgsmeldung vom Typ notice erhält damit einen grünen Hintergrund.
Eine Meldung vom Typ alert wird dagegen rot dargestellt.
Da die Flash-Ausgabe Bestandteil unseres gemeinsamen Layouts ist, müssen wir sie nicht mehr in jeder einzelnen View wiederholen.

Flash-Meldungen nach dem Erstellen eines Users

Erstellen wir nun einen gültigen User, leitet uns der Scaffold anschließend zur Show-Seite weiter.
Dort erscheint beispielsweise:
User was successfully created.
Die Meldung wird nicht mehr von users/show.html.erb selbst ausgegeben, sondern zentral durch unser Application-Layout.
7.webp 39.5 KB

Flash-Meldungen nach dem Löschen eines Users

Dasselbe gilt nach dem Löschen.
Der Scaffold leitet anschließend zurück zur Benutzerübersicht und setzt eine entsprechende Flash-Meldung.
Beispielsweise:
User was successfully destroyed.
Auch diese Meldung wird automatisch an derselben Stelle im Layout dargestellt.
8.webp 34 KB
Damit haben wir eine zentrale Flash-Ausgabe, die nicht nur für unsere User-Views funktioniert. Auch andere Controller und Ressourcen unserer Anwendung können dieselbe Darstellung verwenden.
Unsere Basis-App besitzt damit einen gemeinsamen Seitencontainer, grundlegende Formularstyles, eine übersichtliche Darstellung von Validierungsfehlern und eine zentrale Ausgabe von Flash-Meldungen.
Diese Grundlage können wir für weitere kleine Rails-Beispielanwendungen und Tutorials wiederverwenden.
Melde dich an, um einen Kommentar zu schreiben