<%= note.content %> "> [Redigera]
/ Komplett ">?
Skapad: <%= note.created_at %>
Välkommen till Track 2 of Singing med Sinatra. I del ett granskade vi rutor, hur man arbetar med URI-parametrar, arbetar med formulär, och hur Sinatra skiljer rutter med den HTTP-metod som de begärdes av. Idag ska vi utöka vår kunskap om Sinatra genom att bygga en liten databasdriven app, "Recall", för att ta anteckningar / göra en att göra-lista.
Vi ska använda en SQLite-databas för att lagra anteckningarna, och vi använder DataMapper RubyGem för att kommunicera med databasen. Kör följande inuti ett skal för att installera relevanta Gems:
geminstallation sqlite3 datamapper dm-sqlite-adapter
Beroende på hur du har skapat RubyGems på ditt system, kan du behöva prefix gem installation
med sudo
.
Låt oss hoppa direkt in genom att skapa en ny katalog för projektet och skapa applikationsfilen, recall.rb
. Starta det genom att kräva de relevanta ädelstenarna:
kräver "rubygems" kräver "sinatra" kräver "datamapper"
Notera: Om du kör Ruby 1.9 (som du borde vara) kan du släppa "behöva rubygems" -linjen, eftersom Ruby automatiskt laddar RubyGems i alla fall.
Och konfigurera databasen med följande:
DataMapper :: setup (: default, "sqlite3: // # Dir.pwd /recall.db") klass Notera inkluderar DataMapper :: Resursegenskap: id, seriell egendom: innehåll, text,: krävs => sann egendom: komplett, booleskt: krävs => true,: default => false property: created_at, DateTime-egenskap: updated_at, DateTime-slut DataMapper.finalize.auto_upgrade!
På första raden skapar vi en ny SQLite3-databas i den aktuella katalogen, namngiven recall.db
. Nedan lägger vi faktiskt upp ett Notes-bord i databasen.
Medan vi ringer klassen "Notera", skapar DataMapper tabellen som "Notes". Detta överensstämmer med en konvention som Ruby on Rails och andra ramverk och ORM-moduler följer.
Inom klassen ställer vi upp databasschemat. Tabellen Notes har 5 fält. En id
fält som kommer att vara ett heltal primärtangent och automatisk inkrementering (detta är vad seriell betyder). en innehåll
fält som innehåller text, en booleska komplett
fält och två datetime fält, skapad vid
och updated_at
.
Den allra sista raden instruerar DataMapper att automatiskt uppdatera databasen för att innehålla tabeller och fält som vi har ställt och att göra det igen om vi gör några ändringar i schemat.
Nu, låt oss skapa vår hemsida:
Överst är ett formulär för att lägga till en ny anteckning, och nedan är det alla anteckningar i databasen. För att komma igång lägger du till följande i programfilen, recall.rb
:
få '/' do @notes = Note.all: .order =>: id.desc @title = 'Alla anteckningar' erb: hemänden
Viktig notering: Ta bort pricken ('.
') i :.ordning
. (WordPress störa kodprovet.)
På andra raden ser du hur vi hämtar alla anteckningar från databasen. Om du har använt ActiveRecord (den ORM som används i Rails) tidigare, kommer DataMapper-syntaxen att känna sig mycket bekant. Anteckningarna är tilldelade till @notes
instansvariabel. Det är viktigt att använda instansvariabler (det är variabler som börjar med en @
) så att de kommer att vara tillgängliga från visningsfilen.
Vi ställer in @titel
instansvariabel och ladda visningar / home.erb
visa fil via ERB-parsern.
Skapa visningar / home.erb
visa fil och starta av med följande:
<% # display notes %>
Vi har en enkel formulär som POST till hemsidan ('/'
), och under det är en del ERB-kod som tjänstgör som platshållare för nu.
HTML-standardpartiet bland dig kan ha drabbats av en mindre stroke efter att ha sett att vår hemvyfil inte innehåller någon doktyp eller andra HTML-taggar. Tja, det finns en anledning till det. Skapa en layout.erb
filen i din visningar /
katalog som innehåller följande:
<%= @title + ' | Recall' %> Återkallelse
för att du är för upptagen att komma ihåg
<%= yield %>
De två intressanta delarna här är linjerna 5 och 18. På linje 5 ser du den första användningen av <%=? %>
ERB-taggar. <%=
skiljer sig från det vanliga <%
som det skriver ut vad som är inuti. Så här visar vi vad som helst i @titel
instansvariabel följt av | Återkallelse
för sidans
märka.
På linje 18 är <%= yield %>
. Sinatra kommer att visa detta layout.erb
fil på alla rutter. Och det faktiska innehållet för den rutten kommer att införas varhelst avkastning
är. avkastning
är en term som väsentligen betyder "stanna här, sätt in vad som väntar, fortsätt sedan på".
Starta servern med shotgun recall.rb
i skalet och ta en titt på hemsidan i webbläsaren. Du borde se innehållet från layoutfilen och formuläret från själva home.erb
se.
I layoutfilen inkluderade vi två CSS-filer. Sinatra kan ladda statiska filer (t.ex. din CSS, JS, bilder etc.) från en mapp som heter offentlig/
i rotkatalogen. Så skapa den katalogen, och inuti den två filer: reset.css
och style.css
. Återställningen innehåller återställning av HTML5 Boilerplate CSS:
/ * HTML5? Boilerplate style.css innehåller en återställning, normalisering av teckensnitt och vissa basstilar. kredit är kvar där kredit är förfallen. mycket inspiration togs från dessa projekt: yui.yahooapis.com/2.8.1/build/base/base.css camendesign.com/design/ praegnanz.de/weblog/htmlcssjs-kickstart * / / * html5doctor.com Återställ stilark ( Eric Meyer Reset Reloaded + HTML5 baseline) v1.6.1 2010-09-17 | Författare: Eric Meyer & Richard Clark html5doctor.com/html-5-reset-stylesheet/ * / html, kropp, div, span, objekt, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, före abbr adress cite kod del dfn em img ins kbd q samp liten stark sub sup var var jag dl dt dd ul ol fältet, form, etikett, legend, tabell, bildtext, tbody, tfoot, thead, tr, th, td, artikel, åt sidan, kanfas, detaljer, figcaption, figur, footer, header, hgroup, meny, nav, avsnitt, sammanfattning , tid, markera, ljud, video margin: 0; padding: 0; kant: 0; font-size: 100%; typsnitt: ärv; vertikal-align: baslinje; artikeln, åtgärd, detaljer, figcaption, figur, footer, header, hgroup, meny, nav, avsnitt display: block; blockquote, q quotes: none; blockquote: före, blockquote: after, q: before, q: efter content: "; content: none; ins bakgrundsfärg: # ff9; färg: # 000; textdekoration: none; markera bakgrund -färg: # ff9; färg: # 000; teckensnittstil: kursiv; teckensnitt-vikt: bold; del text-decoration: line-through; abbr [titel], dfn [titel] gränsbotten: 1px punkterad, markör: hjälp; tabell gränshoppning: kollaps; gränsbild: 0; hr display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; input, välj vertical-align: middle; / * END RESET CSS * / / * font normalisering inspirerad av från YUI bibliotekets fonts.css: developer.yahoo.com/yui/ * / body font : 13px / 1.231 sans-serif; * fontstorlek: liten; / * hack behålls för att bevara specificitet * / välj, inmatning, textarea, knapp font: 99% sans-serif; / * normalisera monospace limning * sv. wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome * / pre, kod, kbd, samp font-family: monospace, sans-serif; / * * minimal b ase styles * / body, select, input, textarea / * # 444 ser bättre ut än svart: twitter.com/H_FJ/statuses/11800719859 * / color: # 444; / * Ange din basfontör här, för att tillämpa jämnt * / / * font-family: Georgia, serif; * / / * rubriker (h1, h2, etc) har ingen standard teckenstorlek eller marginal. definiera dem själv. * / h1, h2, h3, h4, h5, h6 font-weight: bold; / * tvinga alltid en rullningsrad i icke-IE: * / html overflow-y: scroll; / * tillgänglig fokusbehandling: people.opera.com/patrickl/experiments/keyboard/test * / a: svävar, a: aktiv disposition: none; a, a: aktiv, a: besökte färg: # 607890; a: svävar färg: # 036; ul, ol margin-left: 2em; ol list-stil-typ: decimal; / * ta bort marginaler för navigeringslistor * / nav ul, nav li margin: 0; list-style: none; list-style-image: none; liten font-size: 85%; starkt, th font-weight: bold; td vertical-align: top; / * set sub, sup utan att påverka linjehöjd: gist.github.com/413930 * / sub, sup font-size: 75%; linjehöjd: 0; position: relativ; sup topp: -0.5em; sub botten: -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: break-word; vaddering: 15px; textarea översvämning: auto; / * www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ * / .ie6 legend, .ie7 legend margin-left: -7px; / * thnx ivannikolic! * / / * justera kryssrutor, radio, textinmatningar med deras etikett av: Thierry Koblentz tjkdesign.com/ez-css/css/base.css * / input [typ = "radio"] vertikaljustering: textbotten; inmatning [typ = "kryssrutan"] vertikal-align: bottom; .ie7 inmatning [typ = "kryssrutan"] vertikaljustering: baslinje; .6 inmatning vertikal-align: text-bottom; / * handmarkör på klickbara inmatningselement * / etikett, inmatning [typ = "knapp"], inmatning [typ = "submit"], inmatning [typ = "bild"], knapp markör: pekare; / * webkit-webbläsare lägger till en 2px-marginal utanför formelementets krom * / knapp, inmatning, välj textarea margin: 0; / * Färger för formgiltighet * / Inmatning: Giltig, Textarea: Giltig Inmatning: Ogiltig, Textarea: Ogiltig Räckvidd: 1px; -moz-box-skugga: 0px 0px 5px röd; -webkit-box-skugga: 0px 0px 5px röd; boxskugga: 0px 0px 5px röd; .no-boxshadow-inmatning: ogiltig, .no-boxshadow textarea: ogiltig bakgrundsfärg: # f0dddd; / * Dessa urvalsdeklarationer måste vara separata. Ingen textskugga: twitter.com/miketaylr/status/12228805301 Också: hetrosa. * / :: - moz-selection background: # FF5E99; färg: #fff; textskugga: ingen; :: urval bakgrund: # FF5E99; färg: #fff; textskugga: ingen; / * j.mp/webkit-tap-highlight-color * / a: länk -webkit-tap-highlight-färg: # FF5E99; / * gör knappar bra i IE: www.viget.com/inspire/styling-the-utton-element-in-internet-explorer/ * / button width: auto; överflöde: synligt; / * bicubisk resizing för IMG: s icke-inhemska storlek: code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ * / .ie7 img -ms-interpolation-mode: bicubic;
Och style.css
innehåller några grundläggande styling för att få appen att se bra ut:
kropp margin: 35px auto; bredd: 640px; header text-align: center; marginal: 0 0 20px; header h1 display: inline; typsnittstorlek: 32px; rubrik h1 a: länk, rubrik h1 a: besökte färg: # 444; text-dekoration: ingen; header h2 font-size: 16px; typsnittstyp: kursiv; färg: # 999; #main margin: 0 0 20px; #add margin: 0 0 20px; #add textarea höjd: 30px; bredd: 510px; vaddering: 10px; gränsen: 1px solid #ddd; # lägg in höjd: 50px; bredd: 100px; marginal: -50px 0 0; gränsen: 1px solid #ddd; bakgrund: vit; #edit textarea höjd: 30px; bredd: 480px; vaddering: 10px; gränsen: 1px solid #ddd; #edit input [typ = submit] höjd: 50px; bredd: 100px; marginal: -50px 0 0; gränsen: 1px solid #ddd; bakgrund: vit; #edit input [typ = checkbox] höjd: 50px; bredd: 20px; artikel border: 1px solid #eee; border-top: none; vaddering: 15px 10px; artikel: förstklassig border: 1px solid #eee; artikel: nth-barn (jämn) bakgrund: #fafafa; article.complete background: # fedae3; artikelsträcka font-size: 0.8em; p marginal: 0 0 5px; . meta font-size: 0.8em; typsnittstyp: kursiv; färg: # 888; .links font-size: 1.8em; linjehöjd: 0,8em; float: right; marginal: -10px 0 0; .links ett display: block; text-dekoration: ingen;
Uppdatera sidan i din webbläsare och allt ska vara snyggare. Oroa dig inte för denna CSS för mycket; det gör bara sakerna lite snyggare!
Just nu om du försöker skicka in formuläret på hemsidan kommer du att få ett rutfel. Låt oss skapa POST-rutten för hemsidan nu:
posta '/' gör n = Note.new n.content = params [: innehåll] n.created_at = Time.now n.updated_at = Time.now n.save omdirigering '/' slutet
Så när en postförfrågan görs på hemsidan skapar vi ett nytt Objekt-objekt i n
(tack vare DataMapper ORM, Note.new
representerar en ny rad i anteckningar
tabell i databasen). De innehåll
fältet är inställt på de inlämnade data från textarea och skapad vid
och updated_at
datetime fält är inställda på aktuell tidstämpel.
Den nya noten sparas sedan, och användaren omdirigerades till hemsidan där den nya noten kommer att visas.
Så vi har lagt till en ny anteckning, men vi kan inte se den på hemsidan ändå eftersom vi inte har skrivit koden för den. Inuti visningar / home.erb
visa fil, ersätt <%# display notes %>
linje med:
<% @notes.each do |note| %>> <% end %><%= note.content %> "> [Redigera]
/ Komplett ">?
Skapad: <%= note.created_at %>
På första raden börjar vi en slinga genom var och en av @notes
(Alternativt kan vi ha skrivit för notering i @notes
, men med ett block, som vi är här, är en bättre övning). På linje 2 ger vi en klass av
komplett
om nuvarande anteckning är inställd på komplett
. Resten ska vara ganska rakt framåt.
Så vi kan lägga till och visa anteckningar. Nu behöver vi bara möjlighet att redigera och ta bort dem.
Du kanske har märkt det i vår home.erb
visa vi satte en [redigera]
länk för varje anteckning till vad som är väsentligen /: Id
, så låt oss skapa den vägen nu:
få '/: id' do @note = Note.get params [: id] @title = "Redigera anteckning ## params [: id]" erb: redigera slutet
Vi hämtar den begärda noten från databasen med hjälp av det angivna ID-kortet, ställa in en @titel
variabel och ladda visningar / edit.erb
visa fil via ERB-parsern.
Ange följande för visningar / edit.erb
se:
<% if @note %>
/ Delete "> Ta bort
<% else %>Not not found.
<% end %>Detta är en ganska enkel vy. En blankett som pekar tillbaka till den aktuella sidan, en textarea innehållande anteckningen och en kryssruta som kontrolleras om anteckningen är inställd på komplett
.
Men titta på den tredje raden. Mystisk. För att förklara detta behöver vi sidospår lite.
Du har hört talas om de två termerna GET och POST.
Men GET och POST är inte de enda "HTTP-verben" - det finns två mer du borde veta om: PUT och DELETE.
Tekniskt sett bör POST endast användas för att skapa något - till exempel skapa en ny anteckning i din fantastiska nya webbapp, till exempel.
PUT är verbet för att ändra något. Och DELETE, du gissade det, är för att ta bort något.
Att ha dessa fyra verb är ett bra sätt att skilja en app upp. Det är logiskt. Tyvärr stöder webbläsare inte faktiskt PUT eller DELETE-förfrågningar, det är därför du aldrig har hört talas om dem tidigare.
Så, om vi vill logga upp vår app uppåt (vilken Sinatra uppmuntrar), måste vi förfalska dessa PUT och DELETE förfrågningar. Du ser vår formulär verkan
är satt till posta
. Det gömda _metod
inmatningsfält som vi har ställt in på sätta
På den tredje raden låter Sinatra falska denna PUT-förfrågan, samtidigt som man använder en POST. Rails, bland andra ramar, gör saker på ett liknande sätt.
Nu har vi faked vår PUT-förfrågan, vi kan skapa en rutt för den:
put '/: id' gör n = Note.get params [: id] n.content = params [: innehåll] n.complete = params [: complete]? 1: 0 n.updated_at = Time.now n.save omdirigering '/' slutet
Det är allt ganska enkelt. Vi får den relevanta anteckningen med hjälp av ID: n i URI: n, sätter fälten till de nya värdena, sparar och omdirigerar hem. Lägg märke till hur vi på fjärde raden använder en ternär operatör för att ställa in n.complete
till 1
om params [: kompletta]
existerar, eller 0
annat. Det beror på att värdet på en kryssruta endast lämnas in med ett formulär om det är markerat, så vi bara söker efter att det finns det.
I vår edit.erb
Visa, vi lade till en "Radera" länk till vad som i huvudsak är sökvägen /: Id / delete
. Lägg till detta i din ansökningsfil:
få '/: id / delete' gör @note = Note.get params [: id] @title = "Bekräfta radering av anteckning ## params [: id]" erb: radera slutet
På den här sidan får vi bekräftelse från användaren att de faktiskt vill ta bort denna anteckning. Skapa visningsfilen på visningar / delete.erb
med följande:
<% if @note %><% else %>Är du säker på att du vill radera följande anteckning: "<%= @note.content %>"?
Not not found.
<% end %>Observera att precis som hur vi faktade en PUT-förfrågan genom att ställa in en dold _metod
Inmatningsfältet, vi fakar nu en DELETE-förfrågan.
Jag är säker på att du hänger med det här just nu. Radera raden är:
delete '/: id' gör n = Note.get params [: id] n.destroy omdirigera '/' slutet
Testa! Du ska nu kunna visa, lägga till, redigera och ta bort anteckningar. Det finns bara en sak till?
Just nu om du vill ange en anteckning som komplett
Du måste gå in i Redigera och markera rutan på den sidan. Låt oss göra processen lite enklare.
Tillbaka när vi startade huvudsidan inkluderade vi a /: Id / komplett
länk på varje anteckning. Låt oss göra den rutten nu, som helt enkelt ska ange en anteckning som fullständig (eller ofullständig om den redan var klar att slutföra):
få '/: id / complete' gör n = Note.get params [: id] n.complete = n.complete? 0: 1 # flip it n.updated_at = Time.now n.save omdirigering '/' slutet
Du och Sinatra drar av en crackin duet! Du har väldigt snabbt skrivit en enkel webbapp som utför alla CRUD-operationer du förväntar dig att en app ska göra. Den är skriven i super-sexig ren Ruby-kod och är åtskild i sina logiska delar.
I den sista delen av Singing med Sinatra, Encore förbättrar vi felhantering, skyddar appen från XSS och skapar ett RSS-flöde för anteckningarna.
Notera: Du kan bläddra i de slutliga projektfilerna för denna handledning på GitHub.