Bine ați revenit la cântând cu Sinatra! În această a treia și ultima parte vom extinde aplicația "Recall" pe care am construit-o în lecția anterioară. Vom adăuga un feed RSS la aplicație cu ajutorul unei gem-uri Builder incredibil de util, ceea ce face ca crearea fișierelor XML în Ruby să fie o bucată de prăjitură. Vom învăța cât de ușor va face Sinatra să scape de codul HTML de la utilizatori pentru a preveni atacurile XSS și vom îmbunătăți codul de eroare.
Regula generală atunci când se creează aplicații web trebuie să fie paranoică. Paranoid că fiecare dintre utilizatorii dvs. va ieși să vă aducă prin distrugerea site-ului dvs. sau prin atacarea altor utilizatori prin intermediul acestuia. În aplicația dvs., încercați să adăugați o notă nouă cu următorul conținut:
Hopa
În prezent, utilizatorii noștri sunt liberi să introducă orice HTML care le place. Acest lucru lasă aplicația deschise spre atacurile XSS unde un utilizator poate intra în JavaScript greșit pentru a ataca sau pentru a îndrepta alți utilizatori ai site-ului. Deci, primul lucru pe care trebuie să-l facem este să eliminăm conținutul trimis de utilizatori, astfel încât codul de mai sus să fie convertit în entități HTML, cum ar fi:
Hopa
Pentru a face acest lucru, adăugați următorul bloc de cod la dvs. recall.rb
fișier, de exemplu, în cadrul DataMapper.auto_upgrade!
linia:
ajutătorii includ Rack :: Utils alias_method: h,: escape_html sfârșit
Acesta include un set de metode furnizate de Rack. Acum avem acces la a h ()
metoda de a scapa HTML.
Pentru a scăpa de HTML în pagina de pornire, deschideți vizualizari / home.erb
vizualizați fișierul și schimbați <%= note.content %>
line (în jurul liniei 11) la:
<%=h note.content %>
Alternativ, am fi putut scrie acest lucru <%= h(note.content) %>
, dar stilul de mai sus este mult mai comun în comunitatea Ruby. Reîmprospătați pagina și codul HTML trimis ar trebui să fie acum scos și nu executat de browser:
Faceți clic pe linkul "editați" pentru nota cu codul XSS și vă puteți gândi că este în siguranță - totul stă în interiorul unei textarea și astfel nu se execută. Dar dacă adăugăm o notă nouă cu următorul conținut:
Uitați-vă la pagina de editare a acestuia și puteți vedea că am închis textarea și astfel alerta JavaScript este executată. Este clar că trebuie să scăpăm de conținutul notei pe fiecare pagină în care este afișată.
În interiorul tău vizualizari / edit.erb
vizualizați fișierul, evitați conținutul din interiorul lui textarea
prin rularea prin h
(linia 4):
Și faceți același lucru în dvs. vizualizari / delete.erb
fișierul de pe linia 2:
Sigur doriți să ștergeți următoarea notă: "<%=h @note.content %>"?
Acolo îl aveți - suntem în siguranță de la XSS. Nu uitați să scăpați de toate datele trimise de utilizatori atunci când creați alte aplicații web pe viitor!
S-ar putea să vă întrebați "ce este vorba de injecțiile SQL?" Ei bine, DataMapper se ocupă de asta pentru noi, atâta timp cât folosim metodele DataMapper pentru a obține date din baza de date (adică nu execută SQL brut).
O parte importantă a oricărui site dinamic este o formă de feed RSS, iar aplicația Recall nu va fi o excepție! Din fericire incredibil ușor de creat feed-uri grație bijuterie Builder. Instalați-l cu:
gem install builder
În funcție de modul în care ați instalat RubyGems pe sistemul dvs., este posibil să aveți nevoie să prefixați gem install
cu sudo
.
Acum adăugați o nouă rută spre dvs. recall.rb
fișierul de cerere pentru o solicitare GET către /rss.xml
:
primiți '/rss.xml' la @notes = Note.all: order =>: id.desc builder: rss end
Asigurați-vă că adăugați acest traseu undeva de mai sus obține '/: id'
ruta, altfel o cerere pentru rss.xml
ar fi confundat cu un ID post!
În traseu, pur și simplu solicităm toate notele din baza de date și încărcăm a rss.builder
Vezi fișierul. Rețineți cum am folosit motorul ERB pentru a afișa a .ERB
fișier, acum folosim Builder pentru a procesa un fișier. Un fișier Builder este în mare parte un fișier normal Ruby cu o caracteristică specială xml
obiect pentru crearea de etichete XML.
Începeți-vă vizualizari / rss.builder
vizualizați fișierul cu următoarele:
xml.instruct! : .xml,: version => "1.0" xml.rss: version => "2.0" do xml.channel nu se termina
Notă foarte importantă: În prima secundă a blocului de cod de mai sus, eliminați perioada (.
) in text : .xml
. WordPress interferă cu fragmente de cod.
Builder va analiza acest lucru pentru a fi:
Așa că am început prin crearea unei structuri pentru un fișier XML valid. Acum, să adăugăm etichete pentru titlul feed-ului, descrierea și un link înapoi la site-ul principal. Adăugați următoarele în interiorul xml.channel do
bloc:
xml.title "Recall" xml.description "deoarece sunteți prea ocupat să vă amintiți" xml.link request.url
Observați cum obținem adresa URL curentă din cerere
obiect. Am putea codifica acest lucru manual, însă ideea este că puteți încărca aplicația oriunde fără a fi nevoie să modificați coduri obscure.
Există totuși o problemă, legătura este setată acum (de exemplu) http: // localhost: 9393 / rss.xml
. În mod ideal, dorim ca linkul să fie la pagina de pornire și nu înapoi la feed. cerere
obiect are, de asemenea, o PATH_INFO
care este setată la șirul de ruta curent; așa că în cazul nostru, /rss.xml
.
Știind acest lucru, putem folosi acum Ruby's Chomp
pentru a elimina calea de la sfârșitul adresei URL. Schimba xml.link request.url
line la:
request request.url.chomp cererii xml.link.path_info
Legătura din fișierul nostru XML este acum setată la http: // localhost: 9393
. Putem acum trece prin fiecare notă și să creăm un nou element XML pentru aceasta:
@ notes.each face | notă | xml.item do xml.title h note.content xml.link "# cerere.url.chomp request.path_info / # note.id" xml.guid "# request.url.chomp request.path_info / # note.id "xml.pubData Time.parse (note.created_at.to_s) .rfc822 xml.description h note.content end end
Rețineți că pe liniile 3 și 7 evităm utilizarea conținutului notei h
, la fel cum am făcut și în opiniile principale. Este puțin ciudat să afișați același conținut pentru ambele titlu
si Descriere
tag-uri, dar urmărim conducerea Twitter aici și nu există alte date pe care le putem pune acolo.
Pe linia 6 convertim nota creat la
timpul pentru RFC822, formatul necesar pentru orele din fluxurile RSS.
Acum, încercați-l într-un browser! Mergi la /rss.xml
iar notele dvs. ar trebui să fie afișate corect.
Există o mică problemă cu implementarea noastră. În vizualizarea noastră RSS avem titlul și descrierea site-ului. De asemenea, le-am luat în vizualizari / layout.erb
fișier pentru partea principală a site-ului. Dar acum dacă vrem să schimbăm numele sau descrierea site-ului, există două locuri diferite pe care trebuie să le actualizăm. O soluție mai bună ar fi să setați titlul și descrierea în unu locul, apoi să le menționați de acolo.
În interiorul recall.rb
, adăugați direct următoarele două linii în partea de sus a fișierului după necesita
declarații, pentru a defini două constante:
SITE_TITLE = "Recuperare" SITE_DESCRIPTION = "'pentru că sunteți prea ocupat să vă amintiți"
Acum, înapoi înăuntru vizualizari / rss.builder
modificați liniile 4 și 5 la:
xml.title SITE_TITLE xml.description SITE_DESCRIPTION
Și înăuntru vizualizari / layout.erb
schimba
indicați pe linia 5:
<%= "#@title | #SITE_TITLE" %>
Și schimbați h1
și h2
titlurile de titlu de pe liniile 12 și 13 la:
<%= SITE_TITLE %>
<%= SITE_DESCRIPTION %>
De asemenea, ar trebui să includeți un link la feedul RSS din cap
a paginii, astfel încât browserele să poată afișa un buton RSS în bara de adrese. Adăugați următoarele în mod direct înainte de etichetă:
Avem nevoie de o modalitate de a informa utilizatorul când sa întâmplat ceva - sau drept, cum ar fi un mesaj de confirmare când se adaugă o notă nouă, o notă eliminată etc..
Cea mai obișnuită și mai logică modalitate de a realiza acest lucru este prin "mesajele flash" - un mesaj scurt adăugat în sesiunea de browser a utilizatorului, care este afișat și șters pe pagina următoare pe care o vizualizează. Și așa se întâmplă să fie un cuplu de RubyGems pentru a ajuta la realizarea acestui lucru! Introduceți următoarele în Terminal pentru a instala Rack Flash și Sinatra Redirect cu pietre Flash:
gem instalați rack-flash sinatra-redirect-cu-bliț
În funcție de modul în care ați instalat RubyGems pe sistemul dvs., este posibil să aveți nevoie să prefixați gem install
cu sudo
.
Solicitați pietrele prețioase și activați funcționalitatea acestora, adăugând următoarele în partea de sus a paginii dvs. recall.rb
fișier de aplicație:
necesită 'rack-flash' necesită 'sinatra / redirect_with_flash' permite: sesiunile utilizează Rack :: Flash,: sweep => true
Adăugarea unui nou mesaj flash este la fel de simplă flash [: error] = "Ceva a mers prost!"
. Să afișăm o eroare în pagina de pornire când în baza de date nu există note.
Schimba-ti obține '/'
ruta spre:
get '/' do @notes = Note.all: order =>: id.desc @title = 'Toate notele' dacă @ notes.empty? flash [: error] = 'Nu s-au găsit note. Adăugați primul dvs. mai jos. " end erb: sfârșitul casei
Foarte simplu. În cazul în care @notes
instanta este goala, creeaza o noua eroare flash. Pentru a afișa aceste mesaje flash pe pagină, adăugați următoarele la dumneavoastră vizualizari / layout.erb
fișier, înainte de <%= yield %>
:
<% if flash[:notice] %><%= flash[:notice] %> <% end %> <% if flash[:error] %>
<%= flash[:error] %> <% end %>
Și adăugați următoarele stiluri la dvs. publice / style.css
fișier pentru afișarea anunțurilor în verde și erori în roșu:
.notă culoare: verde; .error culoare: roșu;
Acum, pagina dvs. de pornire ar trebui să afișeze mesajul "nu există note" când baza de date este goală:
Acum, să afișăm o eroare sau un mesaj de succes în funcție de faptul dacă o notă nouă ar putea fi adăugată la baza de date. Schimba-ti post '/'
ruta spre:
post '/' do n = Notă.new n.content = params [: content] n.created_at = Time.now n.updated_at = Time.now dacă n.save redirect '/',: note => 'Notă creată cu succes .“ else redirect '/',: error => 'Nota nu a fost salvata'. sfârșitul final
Codul este destul de logic. Dacă nota poate fi salvată, redirecționați-vă către pagina de pornire, cu un mesaj flash "notificare", altfel redirecționați-vă acasă cu un mesaj flash de eroare. Aici puteți vedea sintaxa alternativă pentru setarea unui mesaj flash și redirecționarea paginii oferite de bijuteria Sinatra-Redirect-With-Flash.
De asemenea, ar fi ideal să afișați și o eroare pe pagina "editați nota" dacă nota solicitată nu există. Schimba obține '/: id'
ruta spre:
'': 'id: id =' id = 'id =' id = 'id = "Nu găsesc acea notă." sfârșitul final
Și, de asemenea, pe pagina de solicitare PUT pentru actualizarea unei note. Schimbare pune '/: id'
la:
pune '/: id' do n = Note.get params [: id] cu excepția cazului n redirect '/',: error => "Nu găsesc acea notă". end n.content = params [: conținut] n.complete = params [: complete]? 1: 0 n.updated_at = Time.now dacă n.save redirect '/',: note => 'Notă actualizată cu succes.' alt redirect '/',: error => 'Eroare la actualizarea notei.' sfârșitul final
Schimba obțineți / /: id / delete '
ruta spre:
"@: eroare: editează altul redirecționează" / ',' '': id / delete ' : error => "Nu găsesc acea notă." sfârșitul final
Și cererea corespunzătoare DELETE, ștergeți '/: id'
la:
ștergeți '/: id' do n = Note.get params [: id] dacă n.destroy redirect '/',: note => 'Notă ștersă cu succes'. altceva redirect '/',: error => 'Eroare la ștergerea notei'. sfârșitul final
În cele din urmă, schimbați obține '/: id / complete'
urmăriți următoarele:
primi '/: id / complete' do n = Note.get params [: id] cu excepția cazului n redirect '/',: error => "Nu găsesc acea notă". end n.complete = n.complete? 0: 1 # flip it n.updated_at = Time.now dacă n.save redirect '/',: note => 'Notă marcată ca completă'. altceva redirect '/',: error => 'Eroare la marcarea notei ca fiind completă'. sfârșitul final
O aplicație Web funcțională, sigură și responsabilă de erori, scrisă într-o sumă surprinzător de mică de cod! Pe această mini-serie scurtă am învățat cum să procesăm diferite cereri HTTP cu o interfață RESTful, să ne ocupăm de trimiterile de formulare, să scăpăm de conținut potențial periculos, să conectăm o bază de date, să lucrăm cu sesiunile utilizatorilor pentru a afișa mesaje flash, cum să se ocupe de erorile aplicației.
Dacă doriți să luați aplicația mai departe, vă recomandăm să vă ocupați de autentificarea utilizatorului, cum ar fi cu bijuteria de autentificare Sinatra.
Dacă doriți să implementați aplicația pe un server web, deoarece Sinatra este construit cu Rake, puteți foarte ușor să găzduiți aplicațiile Sinatra pe serverele Apache și Nginx instalând Passenger.
Alternativ, verificați-l pe Heroku, o platformă de găzduire bazată pe Git, care face ca implementarea aplicațiilor web Ruby să fie la fel de simplă git push heroku
(conturile gratuite sunt disponibile!)
Dacă doriți să aflați mai multe despre Sinatra, consultați documentele Readme în profunzime, Paginile de documentare și Cartea Sinatra gratuită.
Notă: fișierele sursă pentru fiecare parte a acestei mini-serii sunt disponibile pe GitHub, împreună cu aplicația finită.