Bygga en Instagram-klon med Ruby on Rails: Del 1

I denna flerdelstudie kommer vi att bygga en Ruby on Rails-app som implementerar utseendet och funktionerna hos den populära sociala mediagiganten Instagram. Vi använder Rails 6, Webpacker 4, Turbolinks, Stimulus Js och Tailwindcss.

DISCLAIMER: Även om syftet med denna självstudie är att dela kunskap och visa hur man implementerar vissa funktioner för inlärning på grund av dess längd och textformat, är det inte riktat till nybörjare Rails-utvecklaren och det är inte en introduktion till Rails. Om du fortfarande inte känner till strukturen för en Rails-applikation rekommenderar jag att du börjar med några grundläggande Rails-tutorials först.

Jag har skapat en Rails 6-app (rc1-version) med Webpacker 4, Turbolinks och den kommande version 1.0 av Tailwindcss. Om du vill följa med kan du klona appen från följande gren:

git klon -b tutorial-start [email protected]: rodloboz / railstagram.git

För att köra pannplattan måste du ha rubin 2.5.3 installerad i din maskin och sedan köra från terminalen inuti den klonade projektmappen:

bunt installera garn installera rails db: skapa db: migrera db: fröskenor s

Målet är att fokusera mer på Rails sätt att implementera funktioner (backend och frontend) och mindre på HTML- och CSS-delarna, så att vi inte dyker för djupt in i dessa ämnen. Som sådan har ovanstående gren redan använt lite styling med Tailwindcss och Fontawesome som återskapar Instagram-looken.

Innan vi börjar, en kort introduktion till Tailwindcss:

Till skillnad från Bootstrap, Foundation, Bulma, är Tailwindcss inte ett UI-kit (det finns inget tema eller det finns inga inbyggda UI-komponenter). Enligt dokumentationen:

Tailwind tillhandahåller mycket komposibla, användbarhetsklasser på låg nivå som gör det enkelt att bygga komplexa användargränssnitt utan att uppmuntra två webbplatser att se likadana ut.

Det är lyhört och tillhandahåller verktyg för att extrahera komponentklasser från upprepade verktygsmönster, vilket gör det enkelt att bygga våra egna egna UI-komponenter:

// Använda Tailwinds verktygsklasser för att // skapa variationer av knappar
.btn-blue {@ tillämpas bg-blue-500 textvit; } .btn-white {@apply text-blue-500} .btn-white: focus {@apply text-blue-400}

Tailwind är skriven i PostCSS och konfigurerad i JavaScript. Jag har därför placerat komponenterna i app / javascript / stilark som ska sammanställas av Webpack. Du hittar den huvudsakliga Tailwind-konfigurationsfilen i app / javascript / stylesheets / config / tailwind.config.js

Användarmodellen

Vi använder Devise för att registrera dig och logga in användare. Instagram kräver att användare registrerar sig med sitt fulla namn och användarnamn utöver det vanliga e-postmeddelandet och lösenordet som Devise redan innehåller som standard.

Låt oss generera en migrering i terminalen:

rails g migration AddAttributToUsers full_name användarnamn: string: uniq om: text

Detta genererar följande migrering:

Instagram använder användarnamnet för att generera webbadresserna till användarprofiler. Som sådan måste användarnamn vara unika, så vi lägger till den begränsningen till databasen i migreringen. Den lägger också till en kolumn om vi kommer att implementera senare.

Glöm inte att rails db: migrera för att tillämpa migreringen.

Låt oss också lägga till en validering till användarmodellen som återspeglar kravet på unikhet. Vi vill också se till att användarnamn endast består av alfanumeriska tecken och inte uteslutande består av siffror. Vi använder ett vanligt uttryck för det. Valideringen bör också vara okänslig för fall.

validerar: användarnamn, närvaro: sant, format: {med: /\A(?=.*??azoem)??azazdd++ZZ/i}, unikhet: {case_sensitive: false}

Instagram kräver inte att användare ska bekräfta lösenordet och tillåter dem att logga in med antingen deras e-postadress eller användarnamn. Gå till de visade genererade vyerna och ta bort lösenordets bekräftelsefält från registreringarna # nya och sessionerna # nya.

Vi måste tillåta användare att tillhandahålla ytterligare parametrar på registreringsformuläret. Lägg till detta till ApplicationController.

Detta gör det möjligt att lägga till de extra attributen till Devises starka params.

Vi måste ändra vårt navfält för att visa användaravataren och en dropdown så att inloggade användare kan logga ut. Du kan se den uppdaterade koden här: https://github.com/rodloboz/railstagram/blob/master/app/views/shared/_navbar.html.erb

Obs! Om du följer läran måste du också lägga till följande i konfigurationsfilen för medvind:

// app / javascript / stylesheets / config / tailwind.config.js
varianter: {borderColors: ['responsive', 'hover', 'focus', 'group-hover'], synlighet: ['responsive', 'group-hover'],}

Och skapa en nedrullningsbar CSS-komponent:

Vi kommer också att använda en vyhjälpare för att bestämma rätt URL för användaravatar. Tills vi implementerar bildöverföringar finns det bara två alternativ: vi kontrollerar om användarens e-postadress är kopplad till ett Gravatar-konto. Om inte, visar vi en standardavatarbild för användaren:

Tillåter användare att logga in med användarnamnet

Som standard tillåter Devise användare att logga in och återställa sitt lösenord genom att ange sin e-postadress. Instagram tillåter användare att ange antingen användarnamn eller e-postadress. Vi måste åsidosätta standardinställningarna för Devise för detta.

Lägg till inloggning som ett attributstillbehör till användarmodellen: attr_accessor: inloggning

Ändra config / initializers / devise.rb för att ha:

config.authentication_keys = [: login]

Och åsidosätta Devises metod för find_for_database_authentication i användarmodellen:

Du kan följa denna wiki för att göra samma sak för lösenordsåterställning: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign_in-using-their-username-or-email -adress

Vid denna tidpunkt bör du testa din ansökan för att se om den fungerar innan du går vidare.

Omfakturerar användarmodellen med en modell Bekymmer:

Just nu börjar din användarmodell se ganska fet ut, med många utformningsmetoder, och vi har bara börjat. Låt oss extrahera all den här koden till en modellproblem. Skapa en fil i app / modeller / bekymmer / authenticable.rb och flytta all den koden från modellen till den här filen:

Då behöver du bara lägga till Authenticable till användarmodellen. Se till att testa det igen.

Användarprofil

Instagram använder användarnamnen i roten till deras URL för att komma åt användarprofiler. För att göra det behöver vi följande rutt:

resurser: användare, sökväg: '/', param:: användarnamn, endast:% i [visa]

Detta skapar en showrutt i roten till vår applikation som fångar in användarnamnet i paramerna och skickar det till usercontroller # show. Då måste vi berätta för vår användarmodell hur man skapar URL-parametrarna för sig själv:

# User def to_param användarnamn slut

Här har jag lagt till några klasser för att utforma Front End och ge Instagram känslan. Kom ihåg att vi använder Tailwindcss, så alla våra anpassade komponenter skapas i app / javascript / stilark / komponenter. Du kan kolla in den fullständiga koden i Github-arkivet som delades i slutet av denna handledning.

Följer användare

Slutligen kommer vi att lägga till möjligheten att följa andra användare. Detta kan uppnås med en sammanfogningstabell som ansluter två användare: en följare, refererad av en kolumn follower_id, och en följare eller användaren som följaren följer, refererad av en kolumn follow_id. Låt oss generera modellen:

rails g model Följ

Ändra migrationen i enlighet därmed:

Och extrahera koden till en relevant fråga:

Uppdatera rutten:

Vi kommer att namnge FollowsController under användare och använda en skapa-åtgärd (benämnd follow_path) som kallar följande metod som vi implementerade ovan i frågan och en förstörande åtgärd (benämnd unfollow_path) som kallar den följda åtgärden implementerad i samma problem. Båda åtgärderna lever under samma slutpunkt /: användarnamn / följ och vi använder HTTP-verben POST och DELETE för att skilja mellan de två. (du kan läsa en mer djupgående artikel om möjligheterna till Rails routing här).

Först ser vi till att knappen Följ / avfölj i vyn fungerar korrekt via en vanlig HTML-begäran. Sedan förökar vi det genom att lägga till alternativet fjärrkontroll: sant för dessa länkar. Detta skickar en AJAX-begäran till backend istället för att ladda hela sidan och sedan uppdaterar vi knappen och motsvarande länk med javascript. Jag har extraherat knappkoden i en vy som är delvis för detta ändamål: app / views / users / _follow_btn.html.erb

Counter Caching

Vi vill visa på profilsidan hur många följare en användare har och antalet användare som en användare följer som Instagram gör. Vi kan använda ActiveRecord för att fråga databasen och räkna relevanta Follow-poster, men vi använder oss av en Rails-funktion som kallas counter caching.

Först måste vi lägga till två kolumner i vår användarmodell som kommer att hålla reda på dessa två räknare med följande migrering:

Sedan lägger vi till alternativet counter_cache till Follow-modellen. Detta instruerar Rails att uppdatera användarkolumnerna med rätt antal följare och följa varje gång en Follow-post skapas eller förstörs.

Uppdatera sedan vår vy i enlighet med dessa två nya kolumner och redigera även create.js.erb för att se till att vyn uppdateras under AJAX-förfrågningar:

Eftersom @user-instansen laddas innan counter_caches aktiveras och innan räknarens kolumner uppdateras varje gång en användare följer eller följer upp en annan användare, måste vi ladda om instansen för att visa rätt antal följare och följa. Vi gör detta genom att lägga till @ user.reload inuti blocket i att skapa och förstöra åtgärder för FollowsController.

Slutligen lägger vi till Stimulus för att ta hand om mångfalden av följarna. Vi kan använda Rails pluralize-metoden, men Stimulus kommer också att vara praktiskt senare.

Installera stimulans i terminalen:

paket exec rails webpacker: install: stimulus

Stimulus fungerar genom att strö HTML-element i vyn med dataattribut som hänvisar till stimuluskontrollanter och mål och händelseåtgärder. I våra användare # show-vy lägger vi till kontrollenheten till huvudelementet: .

Vi måste då ange målelementet där vi ska läsa det faktiska antalet följare, och målet där vi kommer att injicera ordet Follower i det enda eller flertalsform. Detta görs genom att lägga till ett datamålattribut till de relevanta elementen:

Sedan ställer vi in ​​vår follow / unfollow-knapp för att lyssna till ajax: framgångshändelsen med ett data-action-attribut och uppdatera följarens meddelande / ord med stimulans:

Och stimulansstyrenheten ser så här ut:

Det är det för del 1 av denna tutorial. Vi fortsätter vår Instagram-klon i del 2. Du kan kontrollera hela koden för den här delen https://github.com/rodloboz/railstagram/tree/tutorial-part1

OBS: Tack till Juliette Chevalier för förbättringsförslag till den här artikeln och för att stoppa felfel och fel.