Erstellen eines Instagram-Klons mit Ruby on Rails: Teil 1

In diesem mehrteiligen Tutorial werden wir eine Ruby on Rails-App erstellen, die das Aussehen und die Funktionen des beliebten Social-Media-Riesen Instagram implementiert. Wir werden Rails 6, Webpacker 4, Turbolinks, Stimulus Js und Tailwindcss verwenden.

HAFTUNGSAUSSCHLUSS: Während der Zweck dieses Tutorials darin besteht, Wissen auszutauschen und zu zeigen, wie bestimmte Lernfunktionen implementiert werden, richtet es sich aufgrund seiner Länge und seines Textformats nicht an den unerfahrenen Rails-Entwickler und ist keine Einführung in Rails. Wenn Sie mit der Struktur einer Rails-Anwendung noch nicht vertraut sind, empfehle ich, zunächst mit einigen grundlegenden Rails-Tutorials zu beginnen.

Ich habe eine Rails 6-App (RC1-Version) mit Webpacker 4, Turbolinks und der kommenden Version 1.0 von Tailwindcss eingerichtet. Wenn Sie mitmachen möchten, können Sie die App aus dem folgenden Zweig klonen:

Git-Klon -b Tutorial-Start [email protected]: rodloboz / railstagram.git

Um die Boilerplate auszuführen, muss Ruby 2.5.3 auf Ihrem Computer installiert sein und dann vom Terminal im geklonten Projektordner ausgeführt werden:

Bündel installieren Garn installieren Schienen db: erstellen db: migrieren db: Seed Rails s

Ziel ist es, uns mehr auf die Rails-Methode zur Implementierung von Funktionen (Backend und Frontend) und weniger auf die HTML- und CSS-Teile zu konzentrieren, damit wir nicht zu tief in diese Themen eintauchen. Aus diesem Grund wurde in der obigen Verzweigung bereits ein Stil mit Tailwindcss und Fontawesome angewendet, um den Instagram-Look wiederherzustellen.

Bevor wir jedoch beginnen, eine kurze Einführung in Tailwindcss:

Im Gegensatz zu Bootstrap, Foundation, Bulma ist Tailwindcss kein UI-Kit (es gibt kein Thema oder keine integrierten UI-Komponenten). Laut Dokumentation:

Tailwind bietet hochkomposierbare Dienstprogrammklassen auf niedriger Ebene, mit denen sich komplexe Benutzeroberflächen einfach erstellen lassen, ohne dass zwei Websites gleich aussehen müssen.

Es reagiert und bietet Tools zum Extrahieren von Komponentenklassen aus wiederholten Dienstprogrammmustern, sodass Sie ganz einfach unsere eigenen benutzerdefinierten UI-Komponenten erstellen können:

// Verwenden der Dienstprogrammklassen von Tailwind zum // Erstellen von Variationen von Schaltflächen
.btn-blue {@apply bg-blue-500 text-white; } .btn-white {@apply text-blue-500} .btn-white: Fokus {@apply text-blue-400}

Rückenwind ist in PostCSS geschrieben und in JavaScript konfiguriert. Ich habe daher die Komponenten in App / Javascript / Stylesheets platziert, die von Webpack kompiliert werden sollen. Sie finden die Hauptkonfigurationsdatei für Rückenwind in app / javascript / stylesheets / config / tailwind.config.js

Das Benutzermodell

Wir verwenden Devise, um Benutzer anzumelden und anzumelden. Bei Instagram müssen sich Benutzer zusätzlich zu der üblichen E-Mail-Adresse und dem Passwort, die Devise standardmäßig enthält, mit ihrem vollständigen Namen und Benutzernamen anmelden.

Lassen Sie uns eine Migration im Terminal generieren:

Schienen g Migration AddAttributesToUsers vollständiger Name Benutzername: Zeichenfolge: uniq about: text

Dies erzeugt die folgende Migration:

Instagram verwendet den Benutzernamen, um die URLs von Benutzerprofilen zu generieren. Daher müssen Benutzernamen eindeutig sein, daher fügen wir diese Einschränkung der Datenbank bei der Migration hinzu. Außerdem wird eine About-Spalte hinzugefügt, die wir später implementieren werden.

Vergessen Sie nicht, db: migrieren, um die Migration anzuwenden.

Fügen wir dem Benutzermodell auch eine Validierung hinzu, die die Eindeutigkeitsanforderungen widerspiegelt. Wir möchten auch sicherstellen, dass Benutzernamen nur aus alphanumerischen Zeichen bestehen und nicht ausschließlich aus Zahlen bestehen. Wir werden dafür einen regulären Ausdruck verwenden. Bei der Validierung sollte auch die Groß- und Kleinschreibung nicht berücksichtigt werden.

validiert: Benutzername, Anwesenheit: true, Format: {with: /\A(?=.*[az‹)[az\d‹+\Z/i}, Eindeutigkeit: {case_sensitive: false}

Bei Instagram müssen Benutzer das Passwort nicht bestätigen und können sich entweder mit ihrer E-Mail-Adresse oder ihrem Benutzernamen anmelden. Gehen Sie zu den vom Gerät generierten Ansichten und entfernen Sie das Feld zur Kennwortbestätigung aus den Registrierungen # neu und Sitzungen # neu.

Wir müssen den Benutzern erlauben, zusätzliche Parameter im Anmeldeformular anzugeben. Fügen Sie dies dem ApplicationController hinzu.

Dadurch können die zusätzlichen Attribute zu den starken Parametern von Devise hinzugefügt werden.

Wir müssen unsere Navigationsleiste ändern, um den Benutzeravatar und ein Dropdown-Menü anzuzeigen, damit sich angemeldete Benutzer abmelden können. Sie können den aktualisierten Code hier sehen: https://github.com/rodloboz/railstagram/blob/master/app/views/shared/_navbar.html.erb

Hinweis: Wenn Sie dem Lernprogramm folgen, müssen Sie der Konfigurationsdatei für Rückenwind außerdem Folgendes hinzufügen:

// app / javascript / stylesheets / config / tailwind.config.js
Varianten: {borderColors: ['Responsive', 'Hover', 'Focus', 'Group-Hover'], Sichtbarkeit: ['Responsive', 'Group-Hover'],}

Und erstellen Sie eine Dropdown-CSS-Komponente:

Wir werden auch einen Ansichtshelfer verwenden, um die richtige Benutzer-Avatar-URL zu ermitteln. Bis wir Bild-Uploads implementieren, gibt es nur zwei Möglichkeiten: Wir prüfen, ob die Benutzer-E-Mail einem Gravatar-Konto zugeordnet ist. Wenn nicht, zeigen wir ein Standard-Benutzer-Avatar-Bild an:

Benutzer können sich mit dem Benutzernamen anmelden

Standardmäßig können Benutzer sich mit Devise anmelden und ihr Kennwort zurücksetzen, indem sie ihre E-Mail-Adresse angeben. Mit Instagram können Benutzer entweder den Benutzernamen oder die E-Mail-Adresse angeben. Dafür müssen wir die Standardeinstellungen von Devise überschreiben.

Fügen Sie dem Benutzermodell die Anmeldung als Attribut-Accessor hinzu: attr_accessor: login

Ändern Sie config / initializers / devise.rb so, dass:

config.authentication_keys = [: login]

Und überschreiben Sie die Methode find_for_database_authentication von Devise im Benutzermodell:

Sie können diesem Wiki folgen, um dasselbe für die Kennwortwiederherstellung zu tun: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign_in-using-their-username-or-email -Adresse

Zu diesem Zeitpunkt sollten Sie Ihre Anwendung testen, um festzustellen, ob sie funktioniert, bevor Sie fortfahren.

Refactoring des Benutzermodells mit einem Modell Bedenken:

Inzwischen sieht Ihr Benutzermodell mit vielen Methoden ziemlich fett aus, und wir haben gerade erst begonnen. Lassen Sie uns den gesamten Code in ein Modellunternehmen extrahieren. Erstellen Sie eine Datei in App / Models / Concerns / Authentable.rb und verschieben Sie den gesamten Code aus dem Modell in diese Datei:

Dann müssen Sie nur noch include Authenticable zum Benutzermodell hinzufügen. Stellen Sie sicher, dass Sie es erneut testen.

Benutzerprofil

Instagram verwendet die Benutzernamen im Stammverzeichnis seiner URL, um auf Benutzerprofile zuzugreifen. Dazu benötigen wir folgende Route:

Ressourcen: Benutzer, Pfad: '/', Parameter :: Benutzername, nur:% i [show]

Dadurch wird eine Showroute im Stammverzeichnis unserer Anwendung erstellt, die den Benutzernamen in den Parametern erfasst und an den Benutzercontroller # show sendet. Dann müssen wir unserem Benutzermodell mitteilen, wie die URL-Parameter für sich selbst generiert werden sollen:

# User def to_param username end

Hier habe ich ein paar weitere Klassen hinzugefügt, um das Frontend zu gestalten und ihm das Instagram-Feeling zu verleihen. Denken Sie daran, dass wir Tailwindcss verwenden, sodass alle unsere benutzerdefinierten Komponenten in app / javascript / stylesheets / components erstellt werden. Sie können den vollständigen Code im Github-Repository überprüfen, das am Ende dieses Lernprogramms freigegeben wurde.

Folgende Benutzer

Schließlich werden wir die Möglichkeit hinzufügen, anderen Benutzern zu folgen. Dies kann mit einer Join-Tabelle erreicht werden, die zwei Benutzer verbindet: einen Follower, auf den durch eine Spalte follower_id verwiesen wird, und einen Follower oder den Benutzer, dem der Follower folgt, auf den durch eine Spalte follow_id verwiesen wird. Lassen Sie uns das Modell generieren:

Schienen g Modell Folgen

Ändern Sie die Migration entsprechend:

Und extrahieren Sie den Code in ein relevantes Anliegen:

Aktualisieren Sie die Routen:

Wir werden den FollowsController unter Benutzern als Namespace verwenden und eine Erstellungsaktion (mit dem Namen follow_path) verwenden, die die oben in dem Anliegen implementierte Methode follow aufruft, und eine Zerstörungsaktion (mit dem Namen unfollow_path), die die in demselben Anliegen implementierte Aktion unfollow aufruft. Beide Aktionen befinden sich unter demselben Endpunkt /: Benutzername / follow und wir verwenden die HTTP-Verben POST und DELETE, um zwischen den beiden zu unterscheiden. (Einen ausführlicheren Artikel über die Möglichkeiten des Rails-Routings finden Sie hier).

Zunächst stellen wir über eine reguläre HTML-Anfrage sicher, dass die Schaltfläche "Folgen / Entfolgen" in der Ansicht ordnungsgemäß funktioniert. Dann bestätigen wir es, indem wir diesen Links die Option remote: true hinzufügen. Dadurch wird eine AJAX-Anfrage an das Backend gesendet, anstatt die gesamte Seite neu zu laden. Anschließend aktualisieren wir die Schaltfläche und den entsprechenden Link mit Javascript. Ich habe den Schaltflächencode zu diesem Zweck in eine Teilansicht extrahiert: app / views / users / _follow_btn.html.erb

Counter Caching

Wir möchten auf der Profilseite die Anzahl der Follower eines Benutzers und die Anzahl der Benutzer anzeigen, denen ein Benutzer wie Instagram folgt. Wir könnten ActiveRecord verwenden, um die Datenbank abzufragen und die relevanten Follow-Datensätze zu zählen, aber wir werden eine Rails-Funktion verwenden, die als Counter-Caching bezeichnet wird.

Zunächst müssen wir unserem Benutzermodell zwei Spalten hinzufügen, die diese beiden Zähler bei der folgenden Migration verfolgen:

Dann fügen wir dem Follow-Modell die Option counter_cache hinzu. Dadurch wird Rails angewiesen, die Benutzerspalten mit der richtigen Anzahl von Followern zu aktualisieren und jedes Mal zu folgen, wenn ein Follow-Datensatz erstellt oder zerstört wird.

Aktualisieren Sie dann unsere Ansicht entsprechend mit diesen beiden neuen Spalten und bearbeiten Sie auch create.js.erb, um sicherzustellen, dass die Ansicht während AJAX-Anforderungen aktualisiert wird:

Da die @ user-Instanz geladen wird, bevor die counter_caches ausgelöst werden und bevor die Zählerspalten jedes Mal aktualisiert werden, wenn ein Benutzer einem anderen Benutzer folgt oder nicht folgt, müssen wir die Instanz neu laden, um die richtige Anzahl von Followern und Followern anzuzeigen. Dazu fügen wir @ user.reload innerhalb des Blocks in den Aktionen zum Erstellen und Zerstören des FollowsController hinzu.

Schließlich werden wir Stimulus hinzufügen, um die Pluralisierung der Anzahl der Follower zu gewährleisten. Wir könnten die Rails-Pluralisierungsmethode verwenden, aber Stimulus wird sich auch später als nützlich erweisen.

Installieren Sie den Stimulus im Terminal:

Bundle Exec Rails Webpacker: Installieren: Stimulus

Stimulus besprüht HTML-Elemente in der Ansicht mit Datenattributen, die auf Stimulus-Controller und Ziele sowie Ereignisaktionen verweisen. In der # show-Ansicht unserer Benutzer fügen wir den Controller dem Header-Element hinzu: .

Wir müssen dann das Zielelement angeben, in dem wir die tatsächliche Anzahl der Follower lesen, und das Ziel, in das wir das Wort Follower in seiner Singular- oder Pluralform einfügen. Dies erfolgt durch Hinzufügen eines Datenzielattributs zu den relevanten Elementen:

Dann richten wir unseren Follow / Unfollow-Button ein, um das Ajax: Success-Ereignis mit einem Datenaktionsattribut anzuhören und die Follower-Nachricht / das Follower-Wort mit Stimulus zu aktualisieren:

Und der Stimulus-Controller sieht folgendermaßen aus:

Das war's für Teil 1 dieses Tutorials. Wir werden unseren Instagram-Klon in Teil 2 fortsetzen. Den vollständigen Code für diesen Teil finden Sie hier https://github.com/rodloboz/railstagram/tree/tutorial-part1

HINWEIS: Vielen Dank an Juliette Chevalier für Verbesserungsvorschläge zu diesem Artikel und für das Stoppen von Tippfehlern und Fehlern.