<%= note.content %> "> [Bewerken]
/ Complete ">?
gemaakt: <%= note.created_at %>
Welkom bij nummer 2 van Singing with Sinatra. In deel één hebben we Routes besproken, hoe te werken met URI-parameters, werken met formulieren en hoe Sinatra routes onderscheidt op basis van de HTTP-methode waartoe ze zijn gevraagd. Vandaag gaan we onze kennis van Sinatra uitbreiden door een kleine database-gestuurde app te bouwen, "Recall", voor het maken van aantekeningen / het maken van een takenlijst.
We gaan een SQLite-database gebruiken om de notities op te slaan en we gebruiken de DataMapper RubyGem om met de database te communiceren. Voer het volgende in een shell uit om de relevante edelstenen te installeren:
gem installeer sqlite3 datamapper dm-sqlite-adapter
Afhankelijk van hoe u RubyGems heeft ingesteld op uw systeem, moet u mogelijk een voorvoegsel gebruiken gem installeren
met sudo
.
Laten we meteen naar binnen springen door een nieuwe map voor het project te maken en het toepassingsbestand te maken, recall.rb
. Begin ermee door de relevante edelstenen te vereisen:
vereisen 'rubygems' vereisen 'sinatra' vereisen 'datamapper'
Notitie: Als je Ruby 1.9 draait (wat je zou moeten zijn), kun je de "require 'rubygems'" laten vallen als Ruby automatisch toch RubyGems laadt.
En stel de database in met de volgende:
DataMapper :: setup (: standaard, "sqlite3: // # Dir.pwd /recall.db") class Opmerking omvat DataMapper :: Resource-eigenschap: id, Seriële eigenschap: inhoud, Tekst,: vereist => echte eigenschap: voltooid, Boolean,: required => true,: default => false property: created_at, DateTime-eigenschap: updated_at, DateTime end DataMapper.finalize.auto_upgrade!
Op de eerste regel zetten we een nieuwe SQLite3-database op in de huidige map met de naam recall.db
. Daaronder stellen we eigenlijk een 'Notes'-tabel in de database in.
Terwijl we de klasse 'Note' aanroepen, maakt DataMapper de tabel als 'Notes'. Dit komt overeen met een conventie die Ruby on Rails en andere frameworks en ORM-modules volgen.
In de klas stellen we het databaseschema op. De tabel 'Notes' heeft 5 velden. Een ID kaart
veld dat een integer primaire sleutel is en automatisch wordt verhoogd (dit is wat 'Serieel' betekent). EEN inhoud
veld met tekst, een boolean compleet
veld en twee datetime velden, gemaakt bij
en updated_at
.
De allerlaatste regel geeft DataMapper opdracht om de database automatisch bij te werken zodat deze de tabellen en velden bevat die we hebben ingesteld, en dit opnieuw te doen als we wijzigingen in het schema aanbrengen.
Laten we nu onze startpagina maken:
Aan de bovenkant is een formulier om een nieuwe notitie toe te voegen, en daaronder staan alle notities in de database. Voeg om aan de slag te gaan het volgende toe aan het toepassingsbestand, recall.rb
:
get '/' do @notes = Note.all: .order =>: id.desc @title = 'All Notes' erb: home einde
Belangrijke notitie: Verwijder de punt ('.
') in :.bestellen
. (WordPress interfereert met het codevoorbeeld.)
Op de tweede regel ziet u hoe we alle notities uit de database ophalen. Als u ActiveRecord (de ORM gebruikt in Rails) eerder hebt gebruikt, zal de syntaxis van DataMapper heel vertrouwd aanvoelen. De bankbiljetten zijn toegewezen aan de @notes
instantievariabele. Het is belangrijk om instantievariabelen te gebruiken (dat zijn variabelen die beginnen met een @
) zodat ze toegankelijk zijn vanuit het weergavebestand.
We hebben de @titel
instantievariabele, en laad de views / home.erb
bekijk het bestand via de ERB-parser.
Maak het views / home.erb
bekijk het bestand en begin met het volgende:
<% # display notes %>
We hebben een eenvoudig formulier dat naar de startpagina POSTS ('/'
), en daaronder is enige ERB-code die voorlopig als tijdelijke aanduiding dient.
De HTML-standaarden die u kent, hebben mogelijk een kleine hersenbloeding gehad nadat we hebben gezien dat ons thuisview-bestand geen doctype of andere HTML-tags bevat. Welnu, daar is een reden voor. Maak een layout.erb
bestand in uw keer bekeken/
map met de volgende:
<%= @title + ' | Recall' %> Terugroepen
omdat je het te druk hebt om te onthouden
<%= yield %>
De twee interessante delen hier zijn lijn 5 en 18. Op regel 5 zie je het eerste gebruik van de <%=? %>
ERB-tags. <%=
is anders dan het gewone <%
omdat het drukt wat er in zit. Dus hier laten we zien wat er in de @titel
instantievariabele gevolgd door | Terugroepen
voor de pagina's
label.
Op lijn 18 is <%= yield %>
. Sinatra zal dit weergeven layout.erb
bestand op alle routes. En de daadwerkelijke inhoud voor die route wordt ingevoegd waar de opbrengst
is. opbrengst
is een term die in essentie betekent "stop hier, voeg alles in wat wacht, ga dan verder".
Start de server op met shotgun recall.rb
in de shell en bekijk de startpagina in de browser. U zou de inhoud van het lay-outbestand en het formulier van het werkelijke moeten zien home.erb
uitzicht.
In het lay-outbestand hebben we twee CSS-bestanden opgenomen. Sinatra kan statische bestanden laden (bijv. Uw CSS, JS, afbeeldingen enz.) Vanuit een map met de naam openbaar/
in de hoofdmap. Dus maak die map aan, en daarbinnen twee bestanden: reset.css
en style.css
. De reset bevat de HTML5 Boilerplate CSS-reset:
/ * HTML5? Boilerplate style.css bevat een reset, lettertype-normalisatie en enkele basisstijlen. het krediet blijft achter waar het krediet verschuldigd is. er is veel inspiratie gehaald uit deze projecten: yui.yahooapis.com/2.8.1/build/base/base.css camendesign.com/design/ praegnanz.de/weblog/htmlcssjs-kickstart * / / * html5doctor.com Reset stylesheet ( Eric Meyer's Reset Reloaded + HTML5 baseline) v1.6.1 2010-09-17 | Auteurs: Eric Meyer & Richard Clark html5doctor.com/html-5-reset-stylesheet/ * / html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre , abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dd, ol, ul, li , veldset, vorm, label, legenda, tabel, bijschrift, tbody, tfoot, thead, tr, th, td, artikel, opzij, canvas, details, figcaption, figuur, footer, header, hgroup, menu, nav, sectie, samenvatting , tijd, markering, audio, video margin: 0; padding: 0; border: 0; font-size: 100%; lettertype: inherit; vertical-align: basislijn; article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section display: block; blockquote, q quotes: none; blockquote: before, blockquote: after, q: before, q: after content: "; content: none; ins background-colour: # ff9; color: # 000; text-decoration: none; mark background -color: # ff9; color: # 000; font-style: italic; font-weight: bold; del text-decoration: line-through; abbr [title], dfn [title] border-bottom: 1px gestippeld; cursor: help; tabel border-collapse: collapse; border-spacing: 0; hr display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; opvulling: 0; invoer, selecteer vertical-align: middle; / * END RESET CSS * / / * lettertype normalisatie geïnspireerd door de fonts van de YUI Library fonts.css: developer.yahoo.com/yui/ * / body font : 13px / 1.231 schreefloos; * lettergrootte: klein; / * hack behouden om de specificiteit te behouden * / select, invoer, tekstveld, knop font: 99% sans-serif; / * normaliseer monospace sizing * en. wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome * / pre, code, kbd, samp font-family: monospace, sans-serif; / * * minimale b ase styles * / body, select, input, textarea / * # 444 ziet er beter uit dan zwart: twitter.com/H_FJ/statuses/11800719859 * / color: # 444; / * stel hier je basislettertype in, om gelijkmatig toe te passen * / / * font-family: Georgia, serif; * / / * headers (h1, h2, etc) hebben geen standaard lettertypegrootte of -marge. definieer die zelf. * / h1, h2, h3, h4, h5, h6 font-weight: bold; / * dwing altijd een schuifbalk in niet-IE: * / html overflow-y: scroll; / * toegankelijke focusbehandeling: people.opera.com/patrickl/experiments/keyboard/test * / a: hover, a: active outline: none; a, a: active, a: visited color: # 607890; a: hover color: # 036; ul, ol margin-left: 2em; ol list-style-type: decimal; / * marges verwijderen voor navigatielijsten * / nav ul, nav li margin: 0; list-style: none; lijst-stijl-afbeelding: geen; klein font-size: 85%; sterk, th font-weight: bold; td vertical-align: top; / * sub, sup instellen zonder de regelhoogte te beïnvloeden: gist.github.com/413930 * / sub, sup font-size: 75%; regelhoogte: 0; positie: relatief; 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; white-space: pre-wrap; white-space: pre-line; word-wrap: breekwoord; opvulling: 15px; textarea overflow: auto; / * www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ * / .ie6 legend, .ie7 legend margin-left: -7px; / * thnx ivannikolic! * / / * vink selectievakjes, radio's, tekstinvoeringen met hun label uit door: Thierry Koblentz tjkdesign.com/ez-css/css/base.css * / input [type = "radio"] vertical-align: text-bottom; invoer [type = "checkbox"] vertical-align: bottom; .ie7 invoer [type = "checkbox"] vertical-align: baseline; .ie6 invoer vertical-align: text-bottom; / * handcursor op klikbare invoerelementen * / label, invoer [type = "knop"], invoer [type = "submit"], invoer [type = "afbeelding"], knop cursor: pointer; / * Webkit-browsers voegen een marge van 2 px toe buiten het chroom van formulierelementen * / knop, invoer, selectie, tekstgebied margin: 0; / * kleuren voor formuliergeldigheid * / invoer: geldig, tekstveld: geldig invoer: invalid, textarea: ongeldig border-radius: 1px; -moz-box-shadow: 0px 0px 5px rood; -webkit-box-shadow: 0px 0px 5px rood; vakschaduw: 0px 0px 5px rood; .no-boxshadow input: invalid, .no-boxshadow textarea: invalid background-color: # f0dddd; / * Deze selectieverklaringen moeten gescheiden zijn. Geen tekstschaduw: twitter.com/miketaylr/status/12228805301 Ook: hot pink. * / :: - moz-selection background: # FF5E99; color: # fff; text-shadow: none; :: selection background: # FF5E99; color: # fff; text-shadow: none; / * j.mp/webkit-tap-highlight-color * / a: link -webkit-tap-highlight-color: # FF5E99; / * maak knoppen leuk in IE: www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ * / button width: auto; overloop: zichtbaar; / * bicubic resizing voor niet-native IMG: code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image- resizing / * / .ie7 img -ms-interpolatie-modus: bicubisch;
En style.css
bevat enkele basisstyling om de app er mooi uit te laten zien:
body margin: 35px auto; breedte: 640 px; header text-align: center; marge: 0 0 20px; header h1 display: inline; lettertypegrootte: 32px; header h1 a: link, header h1 a: visited color: # 444; tekstdecoratie: geen; header h2 font-size: 16px; lettertype-stijl: cursief; kleur: # 999; #main margin: 0 0 20px; #add margin: 0 0 20px; #add textarea height: 30px; breedte: 510 px; opvulling: 10px; border: 1px solid #ddd; #add input height: 50px; breedte: 100 px; marge: -50px 0 0; border: 1px solid #ddd; achtergrond: wit; #edit textarea height: 30px; breedte: 480 px; opvulling: 10px; border: 1px solid #ddd; #edit input [type = submit] height: 50px; breedte: 100 px; marge: -50px 0 0; border: 1px solid #ddd; achtergrond: wit; #bewerkte invoer [type = aanvinken] hoogte: 50px; breedte: 20px; artikel border: 1px solid #eee; border-top: geen; opvulling: 15px 10px; article: first-of-type border: 1px solid #eee; artikel: nth-child (even) background: #fafafa; article.complete background: # fedae3; artikeloverspanning font-size: 0.8em; p margin: 0 0 5px; .meta font-size: 0.8em; lettertype-stijl: cursief; kleur: # 888; .links font-size: 1.8em; regelhoogte: 0.8em; zweven: rechts; marge: -10 px 0 0; . linkt een display: block; tekstdecoratie: geen;
Ververs de pagina in uw browser en alles zou meer gestyled moeten zijn. Maak je niet te veel zorgen om deze CSS; het maakt de dingen er gewoon een beetje mooier uitzien!
Op dit moment krijg je een routefout als je het formulier op de startpagina probeert in te dienen. Laten we nu de POST-route voor de startpagina maken:
post '/' do n = Note.new n.content = params [: inhoud] n.created_at = Time.now n.updated_at = Time.now n.save redirect '/' end
Dus wanneer er een aanvraag wordt gedaan op de startpagina, maken we een nieuw Note-object in n
(dankzij de DataMapper ORM, Note.new
staat voor een nieuwe rij in de aantekeningen
tabel in de database). De inhoud
veld is ingesteld op de verzonden gegevens uit het tekstgebied en de gemaakt bij
en updated_at
datetime-velden worden ingesteld op het huidige tijdstempel.
De nieuwe notitie wordt vervolgens opgeslagen en de gebruiker wordt teruggeleid naar de startpagina waar de nieuwe notitie wordt weergegeven.
Daarom hebben we een nieuwe notitie toegevoegd, maar we kunnen deze nog niet op de startpagina zien, omdat we de code er niet voor hebben geschreven. Binnen in de views / home.erb
bekijk het bestand, vervang de <%# display notes %>
regel met:
<% @notes.each do |note| %>> <% end %><%= note.content %> "> [Bewerken]
/ Complete ">?
gemaakt: <%= note.created_at %>
Op de eerste regel beginnen we een lus door elk van de @notes
(anders hadden we kunnen schrijven voor opmerking in @notes
, maar een blok gebruiken, zoals we hier zijn, is een betere oefening). Op regel 2 geven we de een klasse van
compleet
als de huidige notitie is ingesteld op compleet
. De rest zou vrij rechttoe rechtaan moeten zijn.
We kunnen dus notities toevoegen en bekijken. Nu hebben we alleen de mogelijkheid nodig om ze te bewerken en te verwijderen.
Je hebt het misschien gemerkt in onze home.erb
bekijken we een [Bewerk]
link voor elke notitie naar wat in essentie is /:ID kaart
, dus laten we die route nu maken:
get '/: id' do @note = Note.get params [: id] @title = "Bewerk opmerking ## params [: id]" erb: edit end
We halen de gevraagde notitie uit de database op met behulp van de verstrekte ID, stel a in @titel
variabele, en laad de views / edit.erb
bekijk het bestand via de ERB-parser.
Voer het volgende in voor de views / edit.erb
uitzicht:
<% if @note %>
/ Delete "> Verwijderen
<% else %>Opmerking niet gevonden.
<% end %>Dit is een vrij eenvoudige weergave. Een formulier dat naar de huidige pagina verwijst, een tekstgebied met de inhoud van de notitie en een selectievakje dat wordt gecontroleerd als de notitie is ingesteld op compleet
.
Maar kijk naar de derde regel. Mysterieus. Om dit uit te leggen, moeten we een beetje afwijken.
Je hebt gehoord van de twee termen GET en POST.
Maar GET en POST zijn niet de enige "HTTP-werkwoorden" - er zijn er nog twee die u moet weten: PUT en DELETE.
Technisch gezien zou POST alleen moeten worden gebruikt voor het maken van iets, zoals het maken van een nieuwe notitie in uw geweldige nieuwe web-app, bijvoorbeeld.
PUT is het werkwoord om iets aan te passen. En VERWIJDEREN, je raadt het al, is om iets te verwijderen.
Het hebben van deze vier werkwoorden is een geweldige manier om een app te scheiden. Het is logisch. Helaas ondersteunen webbrowsers eigenlijk geen PUT- of DELETE-verzoeken, en daarom heeft u waarschijnlijk nog nooit van hen gehoord.
Dus als we hier weer op het goede spoor komen, als we onze app logisch willen opsplitsen (wat Sinatra aanmoedigt), moeten we deze PUT- en DELETE-verzoeken vervalsen. Je zult onze formulieren zien actie
ingesteld op post
. Het verborgen _methode
invoerveld waarin we hebben ingesteld leggen
op de derde regel laat Sinatra dit PUT-verzoek vervalsen, terwijl het daadwerkelijk een POST gebruikt. Rails, naast andere frameworks, doen dingen op dezelfde manier.
Nu hebben we ons PUT-verzoek gefingeerd, we kunnen er een route voor maken:
zet '/: id' do n = Note.get params [: id] n.content = params [: content] n.complete = params [: compleet]? 1: 0 n.updated_at = Time.now n.save redirect '/' end
Het is allemaal vrij eenvoudig. We krijgen de relevante notitie met behulp van de ID in de URI, stellen de velden in op de nieuwe waarden, opslaan en omleiden naar huis. Merk op hoe we op de vierde regel een ternaire operator gebruiken om in te stellen n.complete
naar 1
als params [: invullen]
bestaat, of 0
anders. Dit komt omdat de waarde van een selectievakje alleen wordt verzonden met een formulier als het is aangevinkt, dus we controleren alleen of het bestaat.
In onze edit.erb
weergave, hebben we een link 'Verwijderen' toegevoegd aan wat in wezen het pad is /: Id / delete
. Voeg dit toe aan uw sollicitatiebestand:
get '/: id / delete' do @note = Note.get params [: id] @title = "Bevestig de verwijdering van noot ## params [: id]" erb: delete end
Op deze pagina krijgen we een bevestiging van de gebruiker dat deze notitie daadwerkelijk wilt verwijderen. Maak het weergavebestand aan views / delete.erb
met het volgende:
<% if @note %><% else %>Weet je zeker dat je de volgende opmerking wilt verwijderen: "<%= @note.content %>"?
Opmerking niet gevonden.
<% end %>Merk op dat, net zoals we een PUT-verzoek hebben vervalst door een verborgen instelling in te stellen _methode
invoerveld, doen we nu een VERWIJDEREN verzoek.
Ik weet zeker dat je dit nu onder de knie krijgt. De verwijderingsroute is:
delete '/: id' do n = Note.get params [: id] n.destroy redirect '/' end
Probeer het! U zou nu opmerkingen moeten kunnen bekijken, toevoegen, bewerken en verwijderen. Er is nog één ding?
Op dit moment als je een notitie wilt instellen als compleet
je moet naar de weergave Bewerken gaan en het vakje op die pagina aanvinken. Laten we dat proces wat eenvoudiger maken.
Toen we de hoofdpagina hebben opgezet, hebben we er een toegevoegd /: Id / voltooid
link op elke notitie. Laten we die route nu maken, waarbij een notitie gewoon als compleet wordt geplaatst (of onvolledig als deze al was ingesteld om te voltooien):
get '/: id / complete' do n = Note.get params [: id] n.complete = n.complete? 0: 1 # flip it n.updated_at = Time.now n.save redirect '/' end
Jij en Sinatra trekken een knetterend duet! Je hebt heel snel een eenvoudige webapp geschreven die alle CRUD-bewerkingen uitvoert die je van een app zou verwachten. Het is geschreven in super-sexy-schone Ruby-code en is gescheiden in zijn logische delen.
In het laatste deel van Singing with Sinatra, de Encore, verbeteren we de afhandeling van fouten, beveiligen we de app van XSS en creëren we een RSS-feed voor de notities.
Notitie: Je kunt bladeren door de uiteindelijke projectbestanden voor deze tutorial via GitHub.