Mit Sinatra singen Die Rückruf-App

Willkommen zu Track 2 des Singens mit Sinatra. Im ersten Teil haben wir Routen untersucht, wie mit URI-Parametern gearbeitet wird, wie mit Formularen gearbeitet wird und wie Sinatra Routen anhand der HTTP-Methode unterscheidet, von der sie angefordert wurden. Heute erweitern wir unser Wissen über Sinatra, indem wir eine kleine, datenbankgesteuerte App "Recall" zum Erstellen von Notizen / Erstellen einer Aufgabenliste erstellen.

Wir werden eine SQLite-Datenbank verwenden, um die Notizen zu speichern, und den DataMapper RubyGem verwenden, um mit der Datenbank zu kommunizieren. Führen Sie in einer Shell folgendes aus, um die relevanten Gems zu installieren:

gem installiere sqlite3 datamapper dm-sqlite-adapter

Je nachdem, wie Sie RubyGems auf Ihrem System eingerichtet haben, müssen Sie möglicherweise ein Präfix einfügen gem installieren mit Sudo.


Das Aufwärmen

Lassen Sie uns gleich loslegen, indem Sie ein neues Verzeichnis für das Projekt erstellen und die Anwendungsdatei erstellen, Rückruf.rb. Beginnen Sie damit, indem Sie die entsprechenden Edelsteine ​​anfordern:

erfordern 'rubygems' erfordern 'sinatra' erfordern 'datamapper'

Hinweis: Wenn Sie mit Ruby 1.9 arbeiten (was Sie sollten), können Sie die Zeile "Require 'rubygems" "löschen, da Ruby RubyGems trotzdem automatisch lädt.

Und richten Sie die Datenbank folgendermaßen ein:

DataMapper :: setup (: default, "sqlite3: // # Dir.pwd /recall.db") class Hinweis Beachten Sie, dass DataMapper :: Resource-Eigenschaft: id, Serielle Eigenschaft: content, Text,: required => true ist. complete, Boolean,: required => true,: default => false Eigenschaft: created_at, DateTime-Eigenschaft: updated_at, DateTime-Ende DataMapper.finalize.auto_upgrade!

In der ersten Zeile richten wir im aktuellen Verzeichnis eine neue SQLite3-Datenbank mit dem Namen Abruf.db. Darunter bauen wir tatsächlich eine 'Notes'-Tabelle in der Datenbank auf.

Während wir die Klasse 'Note' nennen, erstellt DataMapper die Tabelle als 'Notes'. Dies entspricht einer Konvention, die Ruby on Rails und andere Frameworks und ORM-Module befolgen.

Innerhalb der Klasse richten wir das Datenbankschema ein. Die 'Notes'-Tabelle enthält 5 Felder. Ein Ich würde Feld, das ein Ganzzahl-Primärschlüssel ist und automatisch inkrementiert wird ("Serial"). EIN Inhalt Feld, das Text enthält, ein Boolean Komplett Feld und zwei Datums- / Uhrzeitfelder, hergestellt in und aktualisiert am.

Die letzte Zeile weist DataMapper an, die Datenbank automatisch so zu aktualisieren, dass sie die von uns festgelegten Tabellen und Felder enthält, und dies erneut zu tun, wenn Änderungen am Schema vorgenommen werden.


Die Startseite

Nun erstellen wir unsere Homepage:

Oben befindet sich ein Formular zum Hinzufügen einer neuen Notiz. Darunter befinden sich alle Notizen in der Datenbank. Fügen Sie der Anwendungsdatei zunächst Folgendes hinzu, Rückruf.rb:

get '/' do @notes = Note.all: .order =>: id.desc @title = 'All Notes' erb: home end

Wichtige Notiz: Entferne den Punkt ('.') im :.Auftrag. (WordPress stört das Codebeispiel.)

In der zweiten Zeile sehen Sie, wie wir alle Notizen aus der Datenbank abrufen. Wenn Sie ActiveRecord (das in Rails verwendete ORM) verwendet haben, wird die Syntax von DataMapper sehr vertraut sein. Die Notizen sind der zugeordnet @Anmerkungen Instanzvariable. Es ist wichtig, Instanzvariablen zu verwenden (das sind Variablen, die mit einem beginnen.) @), so dass sie von der Ansichtsdatei aus zugänglich sind.

Wir setzen die @Titel Instanzvariable, und laden Sie die Ansichten / home.erb Datei über den ERB-Parser anzeigen.

Erstellen Sie die Ansichten / home.erb Datei ansehen und mit folgendem Befehl beginnen:

<% # display notes %>

Wir haben ein einfaches Formular, das POST auf die Homepage ('/') und darunter ist ein ERB-Code, der jetzt als Platzhalter dient.


Layouts

Der HTML-Standardwert unter Ihnen hat möglicherweise einen geringfügigen Schlaganfall erlitten, nachdem festgestellt wurde, dass unsere Home-View-Datei keinen Doctype oder andere HTML-Tags enthält. Nun, dafür gibt es einen Grund. Ein ... kreieren layout.erb Datei in Ihrem Ansichten / Verzeichnis, das Folgendes enthält:

    <%= @title + ' | Recall' %>      

Erinnern

Weil Sie zu beschäftigt sind, um sich daran zu erinnern

<%= yield %>

Eine App für Nettuts+.

Die zwei interessanten Teile sind hier die Zeilen 5 und 18. In Zeile 5 sehen Sie die erste Verwendung der <%=? %> ERB-Tags. <%= unterscheidet sich vom gewöhnlichen <% wie es druckt was drin ist. Also hier zeigen wir das, was im ist @Titel Instanzvariable gefolgt von | Erinnern für die Seite </code> Etikett.</p> <p>In Zeile 18 steht <code><%= yield %></code>. Sinatra zeigt dies an <code>layout.erb</code> Datei auf allen Routen. Und der tatsächliche Inhalt für diese Route wird an jeder beliebigen Stelle eingefügt <code>Ausbeute</code> ist. <code>Ausbeute</code> ist ein Begriff, der im Wesentlichen bedeutet "hier aufhören, einfügen, was wartet, dann weiter".</p> <p>Starten Sie den Server mit <code>Schrotflinteückruf.rb</code> in der Shell und schauen Sie sich die Startseite im Browser an. Sie sollten Inhalt aus der Layoutdatei und das Formular aus der tatsächlichen Datei anzeigen <code>home.erb</code> Aussicht.</p> <img src="//accentsconagua.com/img/images_26_3/singing-with-sinatra-the-recall-app_2.png"> <hr> <h2>CSS</h2> <p>In die Layoutdatei haben wir zwei CSS-Dateien eingefügt. Sinatra kann statische Dateien (z. B. CSS, JS, Bilder usw.) aus einem Ordner mit dem Namen laden <code>Öffentlichkeit/</code> im Wurzelverzeichnis. Erstellen Sie dieses Verzeichnis und darin zwei Dateien: <code>reset.css</code> und <code>style.css</code>. Der Reset enthält den HTML5-Boilerplate-CSS-Reset:</p> <pre>/ * HTML5? Boilerplate style.css enthält ein Reset, eine Normalisierung der Schriftart und einige Basisstile. Guthaben verbleibt, wenn Guthaben fällig ist. Viele Inspirationen wurden von diesen Projekten übernommen: yui.yahooapis.com/2.8.1/build/base/base.css camendesign.com/design/ praegnanz.de/weblog/htmlcssjs-kickstart * / / * html5doctor.com Stylesheet zurücksetzen ( Eric Meyers Reset Reloaded + HTML5-Baseline) v1.6.1 2010-09-17 | Autoren: Eric Meyer & Richard Clark html5doctor.com/html-5-reset-stylesheet/ * / html, body, div, span, Objekt, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre , abbr, adresse, zitieren, code, dfn, em, img, ins, kbd, q, samp, klein, stark, sub, sup, var, b, dl, dt, dd, ol, ul, li , fieldset, formular, beschriftung, legende, tabelle, beschriftung, tbody, tfoot, thead, tr, th, td, artikel, beiseite, leinwand, details, figcaption, abbildung, fußzeile, header, hgroup, menü, nav, abschnitt, zusammenfassung , Zeit, Marke, Audio, Video Marge: 0; Polsterung: 0; Grenze: 0; Schriftgröße: 100%; font: erben; vertikal ausrichten: Grundlinie; Artikel, beiseite, Details, Abb., Abbildung, Fußzeile, Kopfzeile, Gruppe, Menü, Navi, Abschnitt Anzeige: Block; blockquote, q Anführungszeichen: keine; blockquote: before, blockquote: after, q: before, q: after content: "; content: none; ins background-color: # ff9; color: # 000; text-decoration: none; mark background -color: # ff9; color: # 000; font-style: italic; font-weight: fett; del text-decoration: line-through; abbr [title], dfn [title] border-bottom: 1px gepunktet; Cursor: help; table border-collapse: collapse; border-spacing: 0; hr display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; Eingabe, wählen Sie vertical-align: middle; / * END RESET CSS * / / * für die Normalisierung der Schriftart, die von YUI Librarys fonts.css inspiriert wurde: developer.yahoo.com/yui/ * / body font : 13px / 1.231 sans-serif; * font-size: small; / * hack wird beibehalten, um die Spezifität zu erhalten * / select, input, textarea, button font: 99% sans-serif; / * Normalisierung der Monospace-Dimensionierung * en. wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome * / pre, Code, kbd, Samp Schriftfamilie: Monospace, Sans-Serif; / * * minimal b ase styles * / body, select, input, Textbereich / * # 444 sieht besser aus als schwarz: twitter.com/H_FJ/statuses/11800719859 * / color: # 444; / * Setze hier deine Basisschrift, um sie gleichmässig anzuwenden * / / * Schriftfamilie: Georgia, serif; * / / * -Header (h1, h2 usw.) haben keine Standardschriftgröße oder -rand. definieren Sie diese selbst. * / h1, h2, h3, h4, h5, h6 font-weight: fett; / * erzwinge immer eine Bildlaufleiste in Nicht-IE: * / html overflow-y: scroll; / * erreichbare Fokusbehandlung: people.opera.com/patrickl/experiments/keyboard/test * / a: hover, a: active Gliederung: keine; a, a: aktiv, a: besucht color: # 607890; a: hover color: # 036; ul, ol margin-left: 2em; ol list-style-type: dezimal; / * Ränder für Navigationslisten entfernen * / nav ul, nav li margin: 0; Listenstil: keine; list-style-image: keine; klein Schriftgröße: 85%; stark, th font-weight: fett; td vertikal-align: top; / * set sub, sup ohne Auswirkungen auf die Zeilenhöhe: gist.github.com/413930 * / sub, sup font-size: 75%; Zeilenhöhe: 0; Position: relativ; sup top: -0.5em; sub bottom: -0.25em; pre / * www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap/ * / white-space: pre; Leerraum: Pre-Wrap; Leerraum: Vorzeile; Zeilenumbruch: Break-Word; Polsterung: 15px; textarea overflow: auto; / * www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ * / .ie6 Legende, .ie7 Legende Rand links: -7px; / * thnx ivannikolic! * / / * Richten Sie die Checkboxen, Radios und Texteingaben mit ihrem Label an: Thierry Koblentz tjkdesign.com/ez-css/css/base.css * / input [type = "radio"] vertical-align: text-bottom; input [type = "checkbox"] vertical-align: bottom; .ie7 input [type = "checkbox"] vertical-align: baseline; .ie6 input vertikal-align: text-bottom; / * Handcursor auf anklickbare Eingabeelemente * / label, Eingabe [Typ = "Schaltfläche"], Eingabe [Typ = "Senden"], Eingabe [Typ = "Bild"], Schaltfläche Cursor: Zeiger; / * Webkit-Browser fügen einen Rand von 2px außerhalb des Formels von Formularelementen hinzu * / button, Eingabe, Auswahl, Textbereich margin: 0; / * Farben für Formulargültigkeit * / Eingabe: gültig, Textbereich: gültig Eingabe: ungültig, Textbereich: ungültig Randradius: 1px; -moz-box-shadow: 0px 0px 5px rot; -webkit-box-shadow: 0px 0px 5px rot; Box-Schatten: 0px 0px 5px rot; .no-boxshadow Eingabe: ungültig, .no-boxshadow Textbereich: ungültig Hintergrundfarbe: # f0dddd; / * Diese Auswahldeklarationen müssen getrennt sein. Kein Textschatten: twitter.com/miketaylr/status/12228805301 Außerdem: Pink. * / :: - moz-selection background: # FF5E99; Farbe: #fff; Text-Schatten: keiner; :: selection background: # FF5E99; Farbe: #fff; Text-Schatten: keiner; / * j.mp/webkit-tap-highlight-color * / a: link -webkit-tap-highlight-color: # FF5E99; / * Die Schaltflächen lassen sich im IE gut abspielen: www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ * / button width: auto; Überlauf: sichtbar; / * bicubic Größenänderung für nicht-native IMG: code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ * / .ie7 img -ms-interpolation-mode: bikubisch; </pre> <p>Und <code>style.css</code> enthält ein paar grundlegende Stylings, um die App hübsch aussehen zu lassen:</p> <pre>body margin: 35px auto; Breite: 640px; header text-align: center; Marge: 0 0 20px; header h1 display: inline; Schriftgröße: 32px; header h1 a: link, header h1 a: besuchte color: # 444; Textdekoration: keine; header h2 font-size: 16px; Schriftstil: kursiv; Farbe: # 999; #main margin: 0 0 20px; #add margin: 0 0 20px; #add textarea height: 30px; Breite: 510px; Polsterung: 10px; Rahmen: 1px fest #ddd; #add input height: 50px; Breite: 100px; Marge: -50px 0 0; Rahmen: 1px fest #ddd; Hintergrund: weiß; #edit textarea height: 30px; Breite: 480px; Polsterung: 10px; Rahmen: 1px fest #ddd; #edit input [type = submit] Höhe: 50px; Breite: 100px; Marge: -50px 0 0; Rahmen: 1px fest #ddd; Hintergrund: weiß; #edit input [type = Ankreuzfeld] height: 50px; Breite: 20px; article border: 1px solid #eee; Rand oben: keine; Polsterung: 15px 10px; article: first-of-type border: 1px fest #eee; article: nth-child (gerade) background: #fafafa; article.complete background: # fedae3; Artikelspanne font-size: 0.8em; p Marge: 0 0 5px; .meta font-size: 0.8em; Schriftstil: kursiv; Farbe: # 888; .links font-size: 1.8em; Zeilenhöhe: 0.8em; schweben rechts; Marge: -10px 0 0; .links a display: block; Textdekoration: keine; </pre> <p>Aktualisieren Sie die Seite in Ihrem Browser und alles sollte mehr gestylt werden. Machen Sie sich nicht zu viele Gedanken über dieses CSS. es sieht einfach nur ein bisschen schöner aus!</p> <img src="//accentsconagua.com/img/images_26_3/singing-with-sinatra-the-recall-app_3.png"> <hr> <h2>Notiz zur Datenbank hinzufügen</h2> <p>Wenn Sie jetzt versuchen, das Formular auf der Homepage zu senden, wird ein Routenfehler angezeigt. Lassen Sie uns jetzt die POST-Route für die Homepage erstellen:</p> <pre>post '/' do n = Note.newn.content = params [: content] n.created_at = Time.now n.updated_at = Time.now n.save umleiten '/' end</pre> <p>Wenn also eine Post-Anfrage auf der Homepage erfolgt, erstellen wir ein neues Note-Objekt in <code>n</code> (Danke an den DataMapper ORM, <code>Hinweis.neu</code> repräsentiert eine neue Zeile in der <code>Anmerkungen</code> Tabelle in der Datenbank). Das <code>Inhalt</code> Feld wird auf die übermittelten Daten aus dem Textbereich und dem Feld gesetzt <code>hergestellt in</code> und <code>aktualisiert am</code> datetime-Felder werden auf den aktuellen Zeitstempel gesetzt.</p> <p>Die neue Notiz wird dann gespeichert und der Benutzer wird zur Startseite zurückgeleitet, auf der die neue Notiz angezeigt wird.</p> <hr> <h2>Anzeigen der Notizen</h2> <p>Wir haben also eine neue Notiz hinzugefügt, die wir aber noch nicht auf der Homepage sehen können, da wir den Code dafür nicht geschrieben haben. In der <code>Ansichten / home.erb</code> Datei anzeigen, ersetzen Sie das <code><%# display notes %></code> Zeile mit:</p> <pre><% @notes.each do |note| %> <article <%= 'class="complete"' if note.complete %>> <p> <%= note.content %> <span>"> [bearbeiten]</span> </p> <p> / complete ">? </p> <p>Erstellt: <%= note.created_at %></p> </article> <% end %></pre> <p>In der ersten Zeile beginnen wir eine Schleife durch jedes der <code>@Anmerkungen</code> (alternativ hätten wir schreiben können <code>für Hinweis in @Notes</code>, Die Verwendung eines Blocks, wie wir hier sind, ist jedoch eine bessere Praxis. In Zeile 2 geben wir die <code><article></code> eine Klasse von <code>Komplett</code> wenn die aktuelle Note auf eingestellt ist <code>Komplett</code>. Der Rest sollte ziemlich geradlinig sein.</p> <hr> <h2>Notiz bearbeiten</h2> <p>So können wir Notizen hinzufügen und anzeigen. Jetzt brauchen wir nur noch die Möglichkeit, sie zu bearbeiten und zu löschen.</p> <p>Das haben Sie vielleicht bei uns bemerkt <code>home.erb</code> sehen wir ein <code>[bearbeiten]</code> Verknüpfen Sie für jede Notiz das Wesentliche <code>/:Ich würde</code>, Lass uns jetzt diese Route erstellen:</p> <pre>get '/: id' do @note = Note.get params [: id] @title = "Notiz bearbeiten params [: id]" erb: edit end</pre> <p>Wir rufen die angeforderte Notiz mit der angegebenen ID aus der Datenbank ab und richten ein <code>@Titel</code> Variable und laden Sie die <code>Ansichten / edit.erb</code> Datei über den ERB-Parser anzeigen.</p> <p>Geben Sie Folgendes für das ein <code>Ansichten / edit.erb</code> Aussicht:</p> <pre><% if @note %> <form action="/<%= @note.id %>"method =" post "> <input type="hidden" name="_method" value="put"> <textarea name="content"><%= @note.content %></textarea> <input type="checkbox" name="complete" <%= "checked" if @note.complete %>> <input type="submit"> </form> <p>/ löschen "> löschen</p> <% else %> <p>Hinweis nicht gefunden.</p> <% end %></pre> <p>Dies ist eine ziemlich einfache Ansicht. Ein Formular, das auf die aktuelle Seite verweist, ein Textfeld mit dem Inhalt der Notiz und ein Kontrollkästchen, das aktiviert wird, wenn die Notiz auf festgelegt ist <code>Komplett</code>.</p> <p>Aber schau dir die dritte Zeile an. Geheimnisvoll Um dies zu erklären, müssen wir ein wenig auf die Spur bringen.</p> <h3>RESTful Services</h3> <p>Sie haben von den beiden Begriffen GET und POST gehört.</p> <ul> <li> <strong>ERHALTEN: </strong>Das Üblichste. Es ist in der Regel für das Anfordern einer Seite und kann mit einem Lesezeichen versehen werden.</li> <li> <strong>POST: </strong> Wird zum Senden von Daten verwendet und kann nicht mit einem Lesezeichen versehen werden.</li> </ul> <p>Aber GET und POST sind nicht die einzigen "HTTP-Verben" - zwei weitere sollten Sie kennen: PUT und DELETE.</p> <p>Technisch gesehen sollte der POST nur zum Erstellen von etwas verwendet werden, z. B. zum Erstellen einer neuen Notiz in Ihrer großartigen neuen Web-App.</p> <p>PUT ist das Verb, um etwas zu ändern. Und DELETE, Sie haben es erraten, dient dazu, etwas zu löschen.</p> <p>Mit diesen vier Verben können Sie eine App gut voneinander trennen. Es ist logisch. Leider unterstützen Webbrowser eigentlich keine PUT- oder DELETE-Anforderungen. Aus diesem Grund haben Sie wahrscheinlich noch nie davon gehört.</p> <p>Um hier wieder auf Kurs zu kommen, wenn wir unsere App logisch aufteilen möchten (was Sinatra ermutigt), müssen wir diese PUT- und DELETE-Anforderungen fälschen. Sie werden unser Formular sehen <code>Aktion</code> ist eingestellt auf <code>Post</code>. Der Versteckte <code>_Methode</code> Eingabefeld, auf das wir eingestellt haben <code>stellen</code> In der dritten Zeile kann Sinatra diese PUT-Anfrage fälschen, während tatsächlich ein POST verwendet wird. In ähnlicher Weise verhalten sich Rails unter anderem.</p> <hr> <h2>Lass uns PUT</h2> <p>Jetzt haben wir unsere PUT-Anfrage gefälscht, und wir können eine Route dafür erstellen:</p> <pre>put '/: id' do n = Note.get params [: id] n.content = params [: content] n.complete = params [: complete]? 1: 0 n.updated_at = Time.now n.save umleiten '/' end</pre> <p>Es ist alles ziemlich einfach. Wir erhalten den entsprechenden Hinweis mithilfe der ID in der URI, setzen die Felder auf die neuen Werte, speichern und leiten die Startseite um. Beachten Sie, wie wir in der vierten Zeile einen ternären Operator zum Setzen verwenden <code>n.pl</code> zu <code>1</code> ob <code>params [: komplettieren]</code> existiert oder <code>0</code> Andernfalls. Dies liegt daran, dass der Wert eines Kontrollkästchens nur dann mit einem Formular übermittelt wird, wenn es markiert ist. Wir prüfen also nur, ob es vorhanden ist.</p> <hr> <h2>Eine Notiz löschen</h2> <p>In unserer <code>edit.erb</code> In dieser Ansicht haben wir einen Link 'Löschen' zu dem Pfad hinzugefügt <code>/: id / delete</code>. Fügen Sie dies Ihrer Bewerbungsdatei hinzu:</p> <pre>get '/: id / delete' do @note = Note.get params [: id] @title = "Löschen des Hinweises ## params [: id]" erb: delete beendet</pre> <p>Auf dieser Seite erhalten Sie vom Benutzer die Bestätigung, dass Sie diese Notiz tatsächlich löschen möchten. Erstellen Sie die Ansichtsdatei unter <code>Ansichten / delete.erb</code> mit den folgenden:</p> <pre><% if @note %> <p>Möchten Sie die folgende Notiz wirklich löschen: <em>"<%= @note.content %>"</em>?</p> <form action="/<%= @note.id %>"method =" post "> <input type="hidden" name="_method" value="delete"> <input type="submit" value="Yes, Delete It!"> "> Abbrechen </form> <% else %> <p>Hinweis nicht gefunden.</p> <% end %></pre> <p>Beachten Sie das, genau wie wir eine PUT-Anfrage gefälscht haben, indem Sie eine verborgene setzen <code>_Methode</code> Eingabefeld, fälschen wir jetzt eine DELETE-Anfrage.</p> <hr> <h2>Die DELETE Route</h2> <p>Ich bin sicher, dass Sie jetzt den Dreh raus haben. Die Löschroute lautet:</p> <pre>delete '/: id' do n = Note.get params [: id] n.destroy umleiten '/' end</pre> <p>Versuch es! Sie sollten jetzt Notizen anzeigen, hinzufügen, bearbeiten und entfernen können. Es gibt nur noch eine Sache? </p> <hr> <h2>Eine Notiz als "abgeschlossen" markieren</h2> <p>Jetzt, wenn Sie eine Notiz als festlegen möchten <code>Komplett</code> Sie müssen in die Bearbeitungsansicht gehen und das Kontrollkästchen auf dieser Seite aktivieren. Lassen Sie uns diesen Prozess etwas einfacher machen.</p> <p>Als wir die Hauptseite eingerichtet haben, haben wir a <code>/: id / complete</code> Link zu jeder Notiz. Lassen Sie uns jetzt diese Route erstellen, die einfach eine Note als vollständig (oder unvollständig, wenn sie bereits abgeschlossen ist) festlegt:</p> <pre>get '/: id / complete' do n = Note.get Parameter [: id] n.complete = n.complete? 0: 1 # Flip it n.updated_at = Time.now n.save Umleitung '/' beenden</pre> <hr> <h2>Fazit</h2> <p>Sie und Sinatra ziehen ein knackendes Duett ab! Sie haben sehr schnell eine einfache Web-App geschrieben, die alle CRUD-Vorgänge ausführt, die Sie von einer App erwarten würden. Es ist in super-sexy-clean-Ruby-Code geschrieben und in seine logischen Teile unterteilt.</p> <p>Im letzten Teil von Singing with Sinatra, dem Encore, verbessern wir die Fehlerbehandlung, sichern die App von XSS und erstellen einen RSS-Feed für die Notizen.</p> <p><strong>Hinweis:</strong> Sie können die endgültigen Projektdateien für dieses Lernprogramm in GitHub durchsuchen.</p> <div class="rek-block"> <center> <ins class="adsbygoogle" style="display:inline-block;width:580px;height:400px" data-ad-client="ca-pub-3810161443300697" data-ad-slot="9434875811"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </center> </div> <div class="h-alltags"> <a href="articles/code">Code</a> </div> </div> </div> </div> </div> <div class="next_posts clearfix"> <div class="n_post"> <div class="next_posts-h1 left_nh1"><a href="/articles/code/singing-with-sinatra.html">Mit Sinatra singen</a></div> <div class="next_posts-img" style="background-image: url('//accentsconagua.com/img/images_26_3/singing-with-sinatra.jpg');"></div> </div> <div class="n_post"> <div class="next_posts-h1 right_nh1"><a href="/articles/code/singing-with-sinatra-the-encore.html">Mit Sinatra singen - The Encore</a></div> <div class="next_posts-img" style="background-image: url('//accentsconagua.com/img/images_26_3/singing-with-sinatra-the-encore.jpg');"></div> </div> </div> <footer> <div class="container"> <div class="footer-langs"> <ul class="site-langs-list"> <li><a href="https://www.accentsconagua.com"><i class="flag flag-DE"></i>Deutsch</a></li> <li><a href="https://fr.accentsconagua.com"><i class="flag flag-FR"></i>Français</a></li> <li><a href="https://nl.accentsconagua.com"><i class="flag flag-NL"></i>Nederlands</a></li> <li><a href="https://no.accentsconagua.com"><i class="flag flag-NO"></i>Norsk</a></li> <li><a href="https://sv.accentsconagua.com"><i class="flag flag-SE"></i>Svenska</a></li> <li><a href="https://it.accentsconagua.com"><i class="flag flag-IT"></i>Italiano</a></li> <li><a href="https://es.accentsconagua.com"><i class="flag flag-ES"></i>Español</a></li> <li><a href="https://ro.accentsconagua.com"><i class="flag flag-RO"></i>Românesc</a></li> </ul> </div> <div class="h-block"><a href="/">accentsconagua.com</a><div class="h-block-a"></div></div> <div class="footer-text"> Interessante Informationen und nützliche Tipps zur Programmierung. Website-Entwicklung, Webdesign und Webentwicklung. Photoshop-Tutorials. Erstellung von Computerspielen und mobilen Anwendungen. Werden Sie von Grund auf professioneller Programmierer. </div> </div> </footer> <div class="search"> <img class="searchico" src="//accentsconagua.com/img/search.svg" alt=""> </div> <div class="modal"> <div class="modal-content"> <span class="close-button">×</span> <input class="searchmain" type="text" id="search-input" placeholder="Suche..."> <ul class="searchli" id="results-container"></ul> </div> </div> <link rel="stylesheet" href="css/flags.css"> <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.css" /> <script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.js"></script> <script> window.addEventListener("load", function(){ window.cookieconsent.initialise({ "palette": { "popup": { "background": "#edeff5", "text": "#838391" }, "button": { "background": "#4b81e8" } }, "theme": "classic", "position": "bottom-right" })}); </script> <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script src="js/scripts.min.js"></script> <script src="js/common.js"></script> <link rel="stylesheet" href="css/fontawesome-all.min.css"> <script> var modal = document.querySelector(".modal"); var trigger = document.querySelector(".search"); var closeButton = document.querySelector(".close-button"); function toggleModal() { modal.classList.toggle("show-modal"); } function windowOnClick(event) { if (event.target === modal) { toggleModal(); } } trigger.addEventListener("click", toggleModal); closeButton.addEventListener("click", toggleModal); window.addEventListener("click", windowOnClick); </script> <script src="https://unpkg.com/simple-jekyll-search@1.5.0/dest/simple-jekyll-search.min.js"></script> <script> SimpleJekyllSearch({ searchInput: document.getElementById('search-input'), resultsContainer: document.getElementById('results-container'), json: '/search.json', searchResultTemplate: '<li><a href="{url}">{title}</a></li>' }) </script> <script src="jquery.unveil2.min.js"></script> <script> $('img').unveil(); </script> </body> </html>