Sang med Sinatra - The Encore

Velkommen tilbake til Singing med Sinatra! I denne tredje og siste delen vil vi utvide appen "Tilbakekall" vi bygde i forrige leksjon. Vi skal legge til et RSS-feed til appen med den utrolig nyttige Builder-perlen, noe som gjør at XML-filer i Ruby er et stykke kake. Vi lærer hvor lett Sinatra gjør å slippe HTML fra brukerinngang for å hindre XSS-angrep, og vi vil forbedre noen av feilhåndterings-koden.


Brukere er dårlige, m'kay

Den generelle regelen når du bygger webapper, skal være paranoid. Paranoid at alle brukere er ute for å få deg ved å ødelegge nettstedet ditt eller angripe andre brukere gjennom det. I appen din kan du prøve å legge til en ny kommentar med følgende innhold:

 woops 

For øyeblikket er brukerne våre gratis i å angi hvilken HTML de liker. Dette lar appen være åpen for XSS-angrep der en bruker kan legge inn skadelig JavaScript for å angripe eller misdirekte andre brukere av nettstedet. Så det første vi trenger å gjøre er å rømme alt brukerinnlevert innhold slik at den ovennevnte koden blir konvertert til HTML-enheter, slik som:

 woops 

For å gjøre dette, legg til følgende kodenavn til din recall.rb fil, for eksempel under DataMapper.auto_upgrade! linje:

 Hjelperne inkluderer Rack :: Utils alias_method: h,: escape_html end

Dette inkluderer et sett med metoder som tilbys av Rack. Vi har nå tilgang til a h () metode for å unnslippe HTML.

Hvis du vil unnslippe HTML på hjemmesiden, åpner du visninger / home.erb vis fil, og endre <%= note.content %> linje (rundt linje 11) til:

 <%=h note.content %>

Alternativt kunne vi ha skrevet dette som <%= h(note.content) %>, men stilen over er mye mer vanlig i Ruby-samfunnet. Oppdater siden, og den innsendte HTML skal nå bli rømt, og ikke utført av nettleseren:

XSS på de andre sidene

Klikk på koblingen "Rediger" for notatet med XSS-koden, og du kan tenke det er trygt - det er alt i en textarea, og det er ikke det som kjøres. Men hva om vi la til et nytt notat med følgende innhold:

  

Ta en titt på redigeringssiden, og du kan se at vi har lukket tekstområdet og så JavaScript-varselet blir utført. Så klart må vi unnslippe notatets innhold på hver side der den vises.

Inne i din visninger / edit.erb vis fil, unnslipp innholdet inne i textarea ved å løpe det gjennom h metode (linje 4):

 

Og gjør det samme i din visninger / delete.erb fil på linje 2:

 

Er du sikker på at du vil slette følgende notat: "<%=h @note.content %>"?

Der har du det - vi er nå trygge fra XSS. Bare husk å unnslippe alle brukerinnleverte data når du oppretter andre webapps i fremtiden!

Du lurer kanskje på "hva med SQL-injeksjoner?" Vel, DataMapper håndterer det for oss like lenge vi bruker DataMappers metoder for å skaffe data fra databasen (dvs. ikke utføre rå SQL).


RSS Feed Massene

En viktig del av et dynamisk nettsted er en form for RSS-feed, og vår Recall-app skal ikke være noe unntak! Heldigvis er det utrolig Lett å lage feeds takket være Builder-perlen. Installer den med:

 perle installasjonsbygger

Avhengig av hvordan du har RubyGems satt opp på systemet, må du kanskje prefiks perle installasjon med sudo.

Legg nå en ny rute til din recall.rb søknadsfil for en GET-forespørsel til /rss.xml:

 få '/rss.xml' gjør @notes = Note.all: order =>: id.desc builder: rss end

Pass på at du legger til denne ruten et sted ovenfor de få '/: id' rute, ellers en forespørsel om rss.xml ville være feil for en post-ID!

I ruten ber vi ganske enkelt alle notater fra databasen, og laster inn en rss.builder se fil. Legg merke til hvordan tidligere vi brukte ERB-motoren for å vise a .erb fil, nå bruker vi Builder til å behandle en fil. En Builder-fil er for det meste en vanlig Ruby-fil med en spesiell xml objekt for å lage XML-koder.

Start din visninger / rss.builder se filen av med følgende:

 xml.instruct! : .xml,: version => "1.0" xml.rss: version => "2.0" gjør xml.channel gjør endeenden

Veldig viktig merknad: På første sekund av kodeblokken ovenfor, fjern perioden (.) i teksten : XML. WordPress forstyrrer kodesnitt.

Builder vil analysere dette ut for å være:

     

Så vi har startet ved å opprette strukturen for en gyldig XML-fil. La oss nå legge til tagger for feedtittelen, beskrivelsen og en link tilbake til hovedsiden. Legg til følgende inne i xml.channel gjør blokkere:

 xml.title "Recall" xml.description "fordi du er for opptatt av å huske" xml.link request.url

Legg merke til hvordan vi får den nåværende nettadressen fra be om gjenstand. Vi kan kodes dette manuelt, men ideen er at du kan laste opp appen hvor som helst uten å måtte bytte uklare kodestykker.

Det er ett problem, men lenken er nå satt til (for eksempel) http: // localhost: 9393 / rss.xml. Ideelt sett vil vi ha linken til hjemmesiden, og ikke tilbake til feedet. De be om objektet har også a PATH_INFO metode som er satt til den nåværende rute strengen; så i vårt tilfelle, /rss.xml.

Å vite dette, kan vi nå bruke Ruby's Chomp metode for å fjerne banen fra slutten av nettadressen. Endre xml.link request.url linje til:

 xml.link request.url.chomp request.path_info

Koblingen i vår XML-fil er nå satt til http: // localhost: 9393. Vi kan nå gå gjennom hvert notat og opprette et nytt XML-element for det:

 @ notater.Ek gjør | notat | xml.item gjør xml.title h note.content xml.link "# request.url.chomp request.path_info / # note.id" xml.guid "# request.url.chomp request.path_info / # note.id "xml.pubDate Time.parse (note.created_at.to_s) .rfc822 xml.description h note.content endeend

Legg merke til at i linjene 3 og 7 unnslipper vi notatets innhold ved hjelp av h, akkurat som vi gjorde i de viktigste visningene. Det er litt rart å vise det samme innholdet for begge tittel og beskrivelse koder, men vi følger Twitters ledelse her, og det er ingen andre data vi kan legge dit.

På linje 6 konverterer vi notatet created_at Tid til RFC822, det nødvendige formatet for ganger i RSS-feeder.

Prøv det nå i en nettleser! Gå til /rss.xml og notatene dine skal vises riktig.


Tørk ikke gjenta selv

Det er et mindre problem med implementeringen vår. I vår RSS-visning har vi tittel og beskrivelse av nettstedet. Vi har også fått dem i visninger / layout.erb fil for hoveddelen av nettstedet. Men nå, hvis vi ønsket å endre navnet eller beskrivelsen av nettstedet, er det to forskjellige steder vi må oppdatere. En bedre løsning ville være å sette tittelen og beskrivelsen i en plasser, referer dem deretter derfra.

Inne i recall.rb applikasjonsfil, legg til følgende to linjer øverst i filen, direkte etter de krever uttalelser, for å definere to konstanter:

 SITE_TITLE = "Tilbakekall" SITE_DESCRIPTION = "'fordi du er for opptatt av å huske"

Nå tilbake innvendig visninger / rss.builder endre linjer 4 og 5 til:

 xml.title SITE_TITLE xml.description SITE_DESCRIPTION

Og inni visninger / layout.erb endre </code> tag på linje 5 til:</p> <pre> <title><%= "#@title | #SITE_TITLE" %>

Og endre h1 og h2 tittelkoder på linjene 12 og 13 til:

 

<%= SITE_TITLE %>

<%= SITE_DESCRIPTION %>

Vi bør også inkludere en lenke til RSS-feed i hode av siden, slik at nettlesere kan vise en RSS-knapp i adressefeltet. Legg til følgende direkte før stikkord:

 

Flashmeldinger Feil og suksesser

Vi trenger noen måte å informere brukeren når noe gikk galt - eller riktig, for eksempel en bekreftelsesmelding når et nytt notat er lagt til, et notat fjernet osv..

Den mest vanlige og logiske måten å oppnå dette på er gjennom "flashmeldinger" - en kort melding lagt inn i brukerens nettlesersesjon, som vises og slettes på neste side de ser. Og det skjer bare så å være et par RubyGems å bidra til å oppnå dette! Skriv inn følgende i Terminal for å installere Rack Flash og Sinatra Redirect med Flash-perler:

 perle installere rack-flash sinatra-omdirigering-med-flash

Avhengig av hvordan du har RubyGems satt opp på systemet, må du kanskje prefiks perle installasjon med sudo.

Krev perler og aktiver funksjonaliteten ved å legge til følgende nær toppen av din recall.rb søknadsfil:

 krever 'rack-flash' krever 'sinatra / redirect_with_flash' enable: økter bruker rack :: Flash,: sweep => true

Å legge til en ny flashmelding er like enkelt som flash [: error] = "Noe gikk galt!". La oss vise en feil på hjemmesiden når det ikke finnes noen notater i databasen.

Forandre din få '/' rute til:

 få '/' do @notes = Note.all: order =>: id.desc @title = 'Alle notater' hvis @ notater.empty? flash [: error] = 'Ingen notater funnet. Legg til din første under. ' End Erb: Hjem End

Veldig enkelt. Hvis @notes instansvariabel er tom, opprett en ny flashfeil. For å vise disse flashmeldingene på siden, legg til følgende i din visninger / layout.erb fil, før <%= yield %>:

 <% if flash[:notice] %> 

<%= flash[:notice] %> <% end %> <% if flash[:error] %>

<%= flash[:error] %> <% end %>

Og legg til følgende stiler til din offentlig / style.css fil for å vise meldinger i grønt og feil i rødt:

 .Legg merke til farge: grønn;  .error color: red; 

Nå skal hjemmesiden din vise meldingen "No Notes Found" når databasen er tom:

La oss nå vise enten en feil- eller suksessmelding, avhengig av om et nytt notat kunne legges til databasen. Forandre din post '/' rute til:

 post '/' gjør n = Note.new n.content = params [: innhold] n.created_at = Time.now n.updated_at = Time.now hvis n.save omadressering '/',: notice => 'Merk opprettet vellykket .' ellers omdirigere '/',: error => 'Kunne ikke lagre notat.' slutten

Koden er ganske logisk. Hvis notatet kan lagres, kan du omdirigere til hjemmesiden, med en "varsel" -melding, ellers omdirigere hjem med en feilmeldingsmelding. Her kan du se den alternative syntaksen for å angi en flashmelding og omdirigere siden som tilbys av Sinatra-Redirect-With-Flash-perlen.

Det ville også være ideelt å også vise en feil på siden "rediger notat" hvis den forespurte notatet ikke eksisterer. Endre få '/: id' rute til:

 få '/: id' do @note = Note.get params [: id] @title = "Rediger notat ## params [: id]" hvis @note erb: rediger omdirigering '/',: error => "Kan ikke finne det notatet." slutten

Og også på PUT-forespørselssiden for når du oppdaterer et notat. Endring sett '/: id' til:

 sett '/: id' gjør n = Note.get params [: id] med mindre n omdirigere '/',: error => "Kan ikke finne det notatet." slutt n.content = params [: content] n.complete = params [: complete]? 1: 0 n.updated_at = Time.now hvis n.save omadresserer '/',: notice => 'Note oppdatert vellykket.' ellers omdirigere '/',: error => 'Feil oppdatering notat.' slutten

Endre få '/: id / delete' rute til:

 få '/: id / delete' gjør @note = Note.get params [: id] @title = "Bekreft sletting av notat ## params [: id]" hvis @note erb: rediger omdirigering '/' : error => "Kan ikke finne det notatet." slutten

Og den tilsvarende DELETE forespørselen, slett '/: id' til:

 slett '/: id' gjør n = Note.get params [: id] hvis n.destroy redirect '/',: notice => 'Merk slettet med hell.' ellers omdirigere '/',: error => 'Feil ved å slette notat.' slutten

Endelig, endre få '/: id / fullført' rute til følgende:

 få '/: id / complete' gjør n = Note.get params [: id] med mindre n viderekobling '/',: error => "Kan ikke finne det notatet." slutt n.complete = n.complete? 0: 1 # flip it n.updated_at = Time.now hvis n.save omadressere '/',: notice => 'Merk merket som fullført.' ellers omdirigere '/',: error => 'Feilsøkingsnotat som komplett.' slutten

Og der har du det!

En fungerende, sikker og feilsøkende webapp skrevet i en overraskende liten mengde kode! I løpet av denne korte mini-serien har vi lært hvordan å behandle ulike HTTP-forespørsler med et RESTful-grensesnitt, håndtere skjemainnlegg, unnslippe potensielt farlig innhold, koble til med en database, jobbe med brukerøkter for å vise flashmeldinger, generere et dynamisk RSS-feed og hvordan å behandle applikasjonsfeil grasiøst.

Hvis du ønsket å ta appen videre, vil du kanskje se på å håndtere brukerautentisering, for eksempel med Sinatra Authentication-perlen.

Hvis du vil distribuere appen på en webserver, da Sinatra er bygget med Rake, kan du veldig lett hoste Sinatra-applikasjonene på Apache og Nginx-servere ved å installere passasjer.

Alternativt kan du sjekke ut Heroku, en Git-drevet hostingplattform som gjør det mulig å distribuere Ruby-webappene dine så enkelt som git push heroku (gratis kontoer er tilgjengelige!)

Hvis du vil lære mer om Sinatra, sjekk ut den svært grundige Readme, dokumentasjonssidene og den gratis Sinatra-boken.

Merk: kildefilene for hver del av denne mini-serien er tilgjengelig på GitHub, sammen med den ferdige appen.