<%= note.content %> "> [Modifica]
/ Completo ">?
Creato: <%= note.created_at %>
Benvenuto in Traccia 2 di Cantare con Sinatra. Nella prima parte, abbiamo esaminato Rotte, come lavorare con i parametri URI, lavorare con i moduli e in che modo Sinatra differenzia le rotte tramite il metodo HTTP da loro richiesto. Oggi estenderemo le nostre conoscenze su Sinatra costruendo una piccola app basata su database, "Recall", per prendere appunti / creare una lista di cose da fare.
Utilizzeremo un database SQLite per archiviare le note e useremo il RubyGem DataMapper per comunicare con il database. Esegui il seguente all'interno di una shell per installare le gemme rilevanti:
gem installa sqlite3 datamapper dm-sqlite-adapter
A seconda di come è stato configurato RubyGems sul tuo sistema, potrebbe essere necessario il prefisso gem installazione
con sudo
.
Iniziamo subito creando una nuova directory per il progetto e creando il file dell'applicazione, recall.rb
. Iniziare richiedendo le gemme rilevanti:
richiedere 'rubygems' richiedono 'sinatra' richiedono 'datamapper'
Nota: Se stai usando Ruby 1.9 (che dovresti essere), puoi rilasciare la riga "require" rubygems "in quanto Ruby carica automaticamente RubyGems in ogni caso.
E impostare il database con il seguente:
DataMapper :: setup (: default, "sqlite3: // # Dir.pwd /recall.db") classe Nota include DataMapper :: Proprietà risorsa: id, proprietà Serial: content, Text,: required => true property: complete, Boolean,: required => true,: default => false proprietà: created_at, proprietà DateTime: updated_at, DateTime end DataMapper.finalize.auto_upgrade!
Sulla prima riga stiamo impostando un nuovo database SQLite3 nella directory corrente, chiamato recall.db
. Di seguito, stiamo configurando una tabella 'Note' nel database.
Mentre chiamiamo la 'Note' della classe, DataMapper creerà la tabella come 'Note'. Questo è in linea con una convenzione che seguono Ruby on Rails e altri framework e moduli ORM.
All'interno della classe, stiamo impostando lo schema del database. La tabella 'Note' avrà 5 campi. Un id
campo che sarà una chiave primaria intera e auto-incrementante (questo è ciò che significa 'Seriale'). UN soddisfare
campo contenente testo, un booleano completare
campo e due campi datetime, created_at
e updated_at
.
L'ultima riga indica a DataMapper di aggiornare automaticamente il database per contenere le tabelle e i campi che abbiamo impostato, e di farlo di nuovo se apportiamo modifiche allo schema.
Ora, creiamo la nostra home page:
In alto c'è un modulo per aggiungere una nuova nota, e sotto di esso ci sono tutte le note nel database. Per iniziare, aggiungi quanto segue al file dell'applicazione, recall.rb
:
get '/' do @notes = Note.all: .order =>: id.desc @title = 'All Notes' erb: home end
Nota importante: Rimuovi il punto ('.
') nel :.ordine
. (WordPress interferisce con il codice di esempio).
Nella seconda riga vedi come recuperiamo tutte le note dal database. Se hai già utilizzato ActiveRecord (l'ORM utilizzato in Rails), la sintassi di DataMapper sarà molto familiare. Le note sono assegnate al @gli appunti
variabile di istanza. È importante utilizzare le variabili di istanza (ovvero le variabili che iniziano con an @
) in modo che siano accessibili dall'interno del file di visualizzazione.
Abbiamo impostato il @titolo
variabile di istanza e carica il views / home.erb
visualizza il file attraverso il parser ERB.
Crea il views / home.erb
visualizza il file e avvialo con il seguente:
<% # display notes %>
Abbiamo una forma semplice quali POST alla home page ('/'
), e al di sotto di questo c'è un codice ERB che funge da segnaposto per ora.
Il lotto degli standard HTML tra di voi potrebbe aver subito un lieve ictus dopo aver visto che il nostro file di visualizzazione home non contiene doctype o altri tag HTML. Bene, c'è una ragione per quello. Creare un layout.erb
file nel tuo visualizzazioni/
directory contenente quanto segue:
<%= @title + ' | Recall' %> Richiamare
perché sei troppo occupato per ricordare
<%= yield %>
Le due parti interessanti qui sono le linee 5 e 18. Sulla linea 5 vedi il primo uso di <%=? %>
Tag ERB. <%=
è diverso dall'ordinario <%
come stampa ciò che è dentro Quindi qui stiamo mostrando ciò che c'è nel @titolo
variabile di istanza seguita da | Richiamare
per la pagina
etichetta.
Sulla linea 18 c'è <%= yield %>
. Sinatra mostrerà questo layout.erb
file su tutte le rotte. E il contenuto effettivo per quella rotta verrà inserito ovunque dare la precedenza
è. dare la precedenza
è un termine che significa essenzialmente "fermati qui, inserisci quello che ti aspetta, poi continua".
Avvia il server con shotgun recall.rb
nella shell, e dare un'occhiata alla home page nel browser. Dovresti vedere il contenuto dal file di layout e il modulo dal reale home.erb
vista.
Nel file di layout abbiamo incluso due file CSS. Sinatra può caricare file statici (ad esempio CSS, JS, immagini ecc.) Da una cartella denominata pubblico/
nella directory principale. Quindi crea quella directory e al suo interno due file: reset.css
e style.css
. Il reset contiene il reset CSS di HTML5 Boilerplate:
/ * HTML5? Boilerplate style.css contiene un reset, la normalizzazione dei font e alcuni stili di base. il credito è lasciato dove il credito è dovuto. molta ispirazione è stata presa da questi progetti: yui.yahooapis.com/2.8.1/build/base/base.css camendesign.com/design/ praegnanz.de/weblog/htmlcssjs-kickstart * / / * html5doctor.com Reimposta il foglio di stile ( Reset Meyer di Eric Meyer + linea base HTML5 v1.6.1 2010-09-17 | Autori: Eric Meyer e Richard Clark html5doctor.com/html-5-reset-stylesheet/ * / html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre , abbr, indirizzo, citare, codice, del, dfn, em, img, ins, kbd, q, samp, piccolo, forte, sub, sup, var, b, i, dl, dt, dd, ol, ul, li , fieldset, forma, etichetta, legenda, tabella, didascalia, tbody, tfoot, thead, tr, th, td, articolo, a parte, canvas, dettagli, figcaption, figure, footer, header, hgroup, menu, nav, section, summary , tempo, contrassegno, audio, video margine: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; articolo, a parte, dettagli, 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-color: # ff9; color: # 000; text-decoration: none; mark background -color: # ff9; color: # 000; font-style: italic; font-weight: bold; del text-decoration: line-through; abbr [titolo], dfn [titolo] border-bottom: 1px punteggiato; cursore: help; tabella border-collapse: collapse; border-spacing: 0; hr display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; input, selezionare vertical-align: middle; / * END RESET CSS * / / * normalizzazione dei font ispirata al font fonts.css: developer.yahoo.com/yui/ * / body della libreria YUI : 13px / 1.231 sans-serif; * font-size: small; / * hack mantenuto per preservare la specificità * / select, input, textarea, button font: 99% sans-serif; / * normalize monospace sizing * it. wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome * / pre, codice, kbd, samp font-family: monospace, sans-serif; / * * minimal b ase styles * / body, select, input, textarea / * # 444 sembra migliore del nero: twitter.com/H_FJ/statuses/11800719859 * / color: # 444; / * imposta qui il tuo carattere di base, per applicare uniformemente * / / * font-family: Georgia, serif; * / / * le intestazioni (h1, h2, ecc.) non hanno font o dimensioni predefinite. definisci te stesso. * / h1, h2, h3, h4, h5, h6 font-weight: bold; / * forza sempre una barra di scorrimento in non-IE: * / html overflow-y: scroll; / * trattamento focalizzato accessibile: 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; / * rimuovi i margini per gli elenchi di navigazione * / nav ul, nav li margin: 0; list-style: none; list-style-image: none; small font-size: 85%; forte, th font-weight: bold; td vertical-align: top; / * imposta sub, sup senza influenzare l'altezza della riga: gist.github.com/413930 * / sub, sup font-size: 75%; altezza della linea: 0; posizione: relativa; 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: break-word; imbottitura: 15px; textarea overflow: auto; / * www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ * / .ie6 legend, .ie7 legend margin-left: -7px; / * thnx ivannikolic! * / / * allinea le caselle di controllo, le radio, gli input di testo con la loro etichetta: 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 vertical-align: text-bottom; / * cursore a forma di mano sugli elementi di input selezionabili * / label, input [type = "button"], input [type = "submit"], input [type = "image"], button cursor: pointer; / * I browser webkit aggiungono un margine di 2px al di fuori del chrome degli elementi del modulo * / button, input, select, textarea margin: 0; / * colori per la validità del modulo * / input: valido, textarea: valido input: non valido, textarea: invalid border-radius: 1px; -moz-box-shadow: 0px 0px 5px rosso; -webkit-box-shadow: 0px 0px 5px rosso; box-shadow: 0px 0px 5px rosso; .no-boxshadow input: invalid, .no-boxshadow textarea: invalid background-color: # f0dddd; / * Queste dichiarazioni di selezione devono essere separate. Nessuna ombra di testo: twitter.com/miketaylr/status/12228805301 Inoltre: 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; / * rendono i pulsanti riproducibili in IE: www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ * / button width: auto; overflow: visibile; / * ridimensionamento bicubico per IMG non nativa: code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ * / .ie7 img -ms-interpolation-mode: bicubic;
E style.css
contiene alcuni stili di base per rendere l'app molto carina:
body margin: 35px auto; larghezza: 640 px; header text-align: center; margine: 0 0 20 px; header h1 display: inline; dimensione del font: 32px; intestazione h1 a: link, intestazione h1 a: visited color: # 444; decorazione del testo: nessuna; header h2 font-size: 16px; stile di carattere: corsivo; colore: n. 999; #main margin: 0 0 20px; #add margin: 0 0 20px; #add textarea height: 30px; larghezza: 510 px; imbottitura: 10px; border: 1px solid #ddd; #add input height: 50px; larghezza: 100 px; margine: -50px 0 0; border: 1px solid #ddd; sfondo: bianco; #edit textarea height: 30px; larghezza: 480 px; imbottitura: 10px; border: 1px solid #ddd; #edit input [type = submit] height: 50px; larghezza: 100 px; margine: -50px 0 0; border: 1px solid #ddd; sfondo: bianco; #edit input [type = checkbox] height: 50px; larghezza: 20px; article border: 1px solid #eee; border-top: nessuno; imbottitura: 15px 10px; articolo: first-of-type border: 1px solid #eee; articolo: nth-child (even) background: #fafafa; article.complete background: # fedae3; article span font-size: 0.8em; p margin: 0 0 5px; .meta font-size: 0.8em; stile di carattere: corsivo; colore: # 888; .links font-size: 1.8em; altezza della linea: 0.8em; float: giusto; margine: -10px 0 0; .links a display: block; decorazione del testo: nessuna;
Aggiorna la pagina nel tuo browser e tutto dovrebbe essere più stilizzato. Non preoccuparti troppo di questo CSS; rende solo le cose un po 'più belle!
In questo momento, se provi a inviare il modulo sulla home page, otterrai un errore di route. Creiamo ora la rotta POST per la home page:
post '/' do n = Note.new n.content = params [: contenuto] n.created_at = Time.now n.updated_at = Time.now n.save reindirizzamento '/' fine
Quindi, quando viene effettuata una richiesta di post sulla home page, creiamo un nuovo oggetto Note in n
(grazie a DataMapper ORM, Note.new
rappresenta una nuova riga nel gli appunti
tabella nel database). Il soddisfare
campo è impostato per i dati inviati dalla textarea e il created_at
e updated_at
i campi datetime sono impostati sul timestamp corrente.
La nuova nota viene quindi salvata e l'utente viene reindirizzato alla home page in cui verrà visualizzata la nuova nota.
Quindi abbiamo aggiunto una nuova nota, ma non possiamo ancora vederla sulla homepage perché non abbiamo scritto il codice per essa. Dentro il views / home.erb
visualizza il file, sostituisci il <%# display notes %>
coincide:
<% @notes.each do |note| %>> <% end %><%= note.content %> "> [Modifica]
/ Completo ">?
Creato: <%= note.created_at %>
Sulla prima riga iniziamo un ciclo attraverso ciascuno dei @gli appunti
(in alternativa, avremmo potuto scrivere per nota in @notes
, ma usare un blocco, come siamo qui, è una pratica migliore). Sulla linea 2, diamo il una classe di
completare
se la nota corrente è impostata su completare
. Il resto dovrebbe essere abbastanza semplice.
Quindi possiamo aggiungere e visualizzare le note. Ora abbiamo solo bisogno di modificarli ed eliminarli.
Potresti averlo notato nel nostro home.erb
vista abbiamo impostato un [modificare]
link per ogni nota a ciò che è essenzialmente /: Id
, quindi creiamo quella rotta ora:
get '/: id' do @note = Note.get params [: id] @title = "Modifica nota ## params [: id]" erb: modifica fine
Ritiriamo la nota richiesta dal database utilizzando l'ID fornito, impostiamo a @titolo
variabile e carica il views / edit.erb
visualizza il file attraverso il parser ERB.
Immettere quanto segue per views / edit.erb
vista:
<% if @note %>
/ Delete "> Elimina
<% else %>Nota non trovata.
<% end %>Questa è una visione abbastanza semplice. Un modulo che rimanda alla pagina corrente, una textarea contenente il contenuto della nota e una casella di controllo che viene controllata se la nota è impostata su completare
.
Ma guarda la terza riga. Misterioso. Per spiegare questo, abbiamo bisogno di tenere traccia di un po '.
Hai sentito parlare dei due termini GET e POST.
Ma GET e POST non sono gli unici "verbi HTTP": ce ne sono altri due che dovresti sapere: PUT e DELETE.
Tecnicamente, il POST dovrebbe essere usato solo per creare qualcosa, ad esempio la creazione di una nuova nota nella tua fantastica nuova app web.
PUT è il verbo per modificare qualcosa. E DELETE, hai indovinato, è per l'eliminazione di qualcosa.
Avere questi quattro verbi è un ottimo modo per separare un'app. È logico. Sfortunatamente, i browser Web non supportano effettivamente richieste PUT o DELETE, motivo per cui probabilmente non ne hai mai sentito parlare prima.
Quindi, tornando in pista qui, se vogliamo dividere logicamente la nostra app (che Sinatra incoraggia), dobbiamo fingere queste richieste PUT e DELETE. Vedrai il nostro modulo azione
è impostato per inviare
. Il nascosto _metodo
campo di input che abbiamo impostato mettere
sulla terza riga lascia Sinatra fingere questa richiesta PUT, mentre effettivamente usa un POST. Rails, tra gli altri framework, fa le cose in modo simile.
Ora abbiamo simulato la nostra richiesta PUT, possiamo creare un percorso per questo:
metti '/: id' do n = Note.get params [: id] n.content = params [: content] n.complete = params [: complete]? 1: 0 n.updated_at = Time.now n.save reindirizza '/' fine
È tutto piuttosto semplice. Otteniamo la nota rilevante usando l'ID nell'URI, impostiamo i campi sui nuovi valori, salviamo e reindirizziamo verso casa. Notate come sulla quarta linea usiamo un operatore ternario per impostare n.complete
a 1
Se params [:] completi
esiste, o 0
altrimenti. Questo perché il valore di una casella di controllo è inviato solo con un modulo se è selezionato, quindi stiamo semplicemente verificando l'esistenza di esso.
Nel nostro edit.erb
vista, abbiamo aggiunto un link 'Elimina' a ciò che è essenzialmente il percorso /: Id / delete
. Aggiungi questo al tuo file di applicazione:
get '/: id / delete' do @note = Note.get params [: id] @title = "Conferma cancellazione della nota ## params [: id]" erb: elimina fine
In questa pagina avremo la conferma da parte dell'utente che in realtà vogliono cancellare questa nota. Crea il file di visualizzazione su views / delete.erb
con il seguente:
<% if @note %><% else %>Sei sicuro di voler eliminare la seguente nota: "<%= @note.content %>"?
Nota non trovata.
<% end %>Si noti che proprio come abbiamo simulato una richiesta PUT impostando un hidden _metodo
campo di input, ora stiamo simulando una richiesta DELETE.
Sono sicuro che ti stai rendendo conto di questo ormai. La rotta di cancellazione è:
cancella '/: id' do n = Note.get params [: id] n.destroy reindirizza '/' fine
Provalo! Ora dovresti essere in grado di visualizzare, aggiungere, modificare e rimuovere note. C'è solo un'altra cosa?
In questo momento se vuoi impostare una nota come completare
devi andare nella vista Modifica e selezionare la casella in quella pagina. Facciamo un po 'più semplice questo processo.
Indietro quando abbiamo impostato la home page principale, abbiamo incluso un /: Id / completo
link su ogni nota. Facciamo ora quella rotta, che semplicemente imposterà una nota come completa (o incompleta se era già stata impostata per il completamento):
get '/: id / complete' do n = Note.get params [: id] n.complete = n.complete? 0: 1 # capovolgi n.updated_at = Time.now n.save reindirizza '/' fine
Tu e Sinatra fate un duetto! Hai scritto molto rapidamente una semplice app Web che esegue tutte le operazioni CRUD che ti aspetteresti che un'app eseguisse. È scritto in codice Ruby super sexy e pulito, ed è separato nelle sue parti logiche.
Nella parte finale di Singing with Sinatra, l'Encore, miglioreremo la gestione degli errori, proteggere l'app da XSS e creare un feed RSS per le note.
Nota: Puoi sfogliare i file di progetto finali per questo tutorial su GitHub.