
Versuchen Sie es: Phoenix-chat .fly.dev
Ein Schritt-für-Schritt-Tutorial zum Erstellen, Testen und Bereitstellen einer Chat-App in Phoenix!
page_controller_test.exsuser_socket.jsmix.exs excoveralls hinzufügencoveralls.jsonPresence hinzufügen, um zu verfolgen, wer online ist Chat -Apps sind die "Hello World" von Beispielen in Echtzeit.
Leider zeigen die meisten Beispiel -Apps ein paar Grundlagen und ignorieren dann den Rest ...? ♀️
Anfänger werden also oft verloren oder verwirrt darüber, was sie als nächstes tun oder lernen sollten!
In sehr wenigen Tutorials werden Tests, Bereitstellungen, Dokumentationen oder andere " Verbesserungen " in Betracht gezogen, die alle Teil der " realen Welt " des Aufbaus und laufenden Apps sind. Das sind also Themen, die wir abdecken , um " die Lücken zu füllen ".
Wir haben dieses Tutorial geschrieben, um Phoenix, Ecto und Channels mit einem praktischen Beispiel Phoenix lernen , das jedem folgen kann .
Dies ist das Beispiel/das Tutorial, das wir uns gewünscht hatten, als wir Elixir lernen, Phoenix ... wenn Sie es nützlich finden, bitte danke!
Ein einfaches Schritt-für-Schritt-Tutorial zeigt Ihnen, wie Sie:
mix phx.new chat "Generator" )Fly.io damit Sie den Leuten Ihre Kreation zeigen können!Zunächst überspringen wir die Konfigurationsdateien und " Phoenix -Interna " absichtlich , weil Sie ( Anfänger ) nicht wissen müssen, um loszulegen . Aber keine Sorge, wir werden bei Bedarf zu ihnen zurückkehren. Wir bevorzugen " Just-in-Time " ( wenn Sie es brauchen ) zu lernen, da es sofort offensichtlich und praktisch ist , warum wir etwas lernen.
Dieses Beispiel gilt für vollständige Anfänger als " My First Phoenix " -App.
Wir versuchen so wenig wie möglich zu übernehmen , aber wenn Sie der Meinung sind, dass wir einen Schritt "übersprungen " haben oder Sie sich aus irgendeinem Grund " festgefahren " fühlen oder Fragen haben ( im Zusammenhang mit diesem Beispiel ), öffnen Sie bitte ein Problem auf GitHub!
Sowohl die @Dwyl- als auch die Phoenix-Gemeinschaften sind superfreundlich , also haben Sie keine Angst/schüchtern.
Wenn Sie Fragen stellen, helfen Sie auch allen, die mit der gleichen Sache festhalten oder festhalten könnten!
Diese Anweisungen zeigen Ihnen, wie Sie die Chat -App von Grund auf neu erstellen .
brew install elixirHinweis : Wenn Sie bereits
Elixirauf Ihrem Mac installiert haben und nur auf die neueste Version ein Upgrade durchführen möchten, rennen Sie:brew upgrade elixir
mix archive.install hex phx_new Grundlegendes Elixir -Syntaxwissen hilft,
Bitte siehe: Dwyl/ Learn-Elixir
Grundlegendes JavaScript- Wissen ist vorteilhaft ( aber nicht wesentlich, da der "Front-End" -Code sehr grundlegend und gut gefördert ist ). Siehe: Dwyl/JavaScript-the-Good-Teile-Notes
Überprüfen Sie, ob Sie die neueste Version von Elixir haben ( die folgende Befehl in Ihrem Terminal ausführen ):
elixir -vSie sollten so etwas sehen wie:
Erlang/OTP 25 [erts-13.1.1] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
Elixir 1.14.1 (compiled with Erlang/OTP 25)Überprüfen Sie, ob Sie die neueste Version von Phoenix haben:
mix phx.new -vSie sollten sehen:
Phoenix installer v1.7.0-rc.2Hinweis : Wenn Ihre
Phoenix-Version neuer ist, können Sie diesen Dokument bitte aktualisieren! Wir versuchen unser Bestes, um es auf dem neuesten Stand zu halten ... aber Ihre Beiträge sind immer willkommen!
In diesem Tutorial verwenden wir Phoenix 1.7-RC2, den zweiten Kandidaten für
Phoenix 1.7. Zum Zeitpunkt des Schreibens ist die neueste stabile Version nichtv1.7. Befolgen Sie die offizielle Anleitung, um diese Version zu verwenden (keine Sorge, sie wird nur einen Befehl ausführen!)->Wenn Sie dies jedoch nach seiner Veröffentlichung lesen, wird
v1.7für Sie installiert und Sie solltenPhoenix installer v1.7.0in Ihrem Terminal sehen.
Bestätigen Sie Postgresql ( damit die App Chat -Nachrichten speichern kann ). Führen Sie den folgenden Befehl aus:
lsof -i :5432Sie sollten die Ausgabe ähnlich wie folgt sehen:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 529 Nelson 5u IPv6 0xbc5d729e529f062b 0t0 TCP localhost:postgresql (LISTEN)
postgres 529 Nelson 6u IPv4 0xbc5d729e55a89a13 0t0 TCP localhost:postgresql (LISTEN) Dies sagt uns, dass PostgreSQL auf TCP -Port 5432 ( dem Standardport ) " zuhören " ist (der Standard -Port).
Wenn der Befehl lsof kein Ergebnis in Ihrem Terminal ergibt, laufen Sie:
pg_isreadyEs sollte Folgendes drucken:
/tmp:5432 - accepting connectionsLassen Sie uns fliegen !
Bevor Sie versuchen, die Chat -App von Grund auf neu zu erstellen, klonen Sie und führen Sie die fertige Arbeitsversion aus, um eine Vorstellung davon zu erhalten, was Sie erwartet.
Führen Sie in Ihrem Terminal den folgenden Befehl aus, um das Repo zu klonen:
git clone [email protected]:dwyl/phoenix-chat-example.git Wechseln Sie in das Verzeichnis von phoenix-chat-example und installieren Sie mit diesem Befehl sowohl die Elixir als auch Node.js Abhängigkeiten:
cd phoenix-chat-example
mix setupFühren Sie die Phoenix -App mit dem Befehl aus:
mix phx.serverWenn Sie die App Localhost: 4000 in zwei weiteren Webbrowsern öffnen, können Sie die in allen angezeigten Chat -Nachrichten sehen, sobald Sie auf die Eingabetaste klicken:

Nachdem Sie bestätigt haben, dass die fertige Phoenix -Chat -App auf Ihrem Computer funktioniert, ist es Zeit, sie von Grund auf neu zu erstellen !
Verzeichnis ändern:
cd ..Und fangen Sie an zu bauen!
Geben Sie in Ihrem Terminalprogramm in Ihrem Localhost den folgenden Befehl ein, um die App zu erstellen:
mix phx.new chat --no-mailer --no-dashboard --no-gettext Dadurch werden die Verzeichnisstruktur und die Projektdateien erstellt.
Wir führen den Befehl
mix phx.newmit den Argumenten--no-mailer--no-dashboard--no-gettextaus, da wir nicht möchten, dass unser Projekt Mailer-Dateien generiert, einPhoenix.LiveDashboardeinbezieht undgettextDateien (füri18n) generiert.
Wenn Sie gefragt werden, " Abhängigkeiten zu holen und zu installieren ? [Yn]", ",", ",", ",", ",", ",",
Geben Sie Y in Ihr Terminal ein, gefolgt von der Taste ENTER ( RETURN ).
Sie sollten sehen: 
Wechseln Sie das Verzeichnis in das chat -Verzeichnis, indem Sie den vorgeschlagenen Befehl ausführen:
cd chatFühren Sie nun den folgenden Befehl aus:
mix setupHINWEIS : Zu diesem Zeitpunkt gibt es bereits eine "App", die (noch) einfach nichts tut ...
Sie könnenmix phx.serverin Ihrem Terminal ausführen - Mach dir keine Sorgen, wenn du einen Fehler beobachtet hast
Nachrichten, das liegt daran, dass wir unsere Datenbank noch nicht erstellt haben.
Wir werden uns in Schritt 6 darum kümmern!
Öffnen Sie vorerst http: // localhost: 4000 in Ihrem Browser
Und Sie werden diedefault"Willkommen auf der Phoenix" -Homepage sehen:

Schalten Sie den Phoenix -Server in Ihrem Terminal mit dem Befehl Strg + c ab .
Führen Sie in Ihrem Terminalfenster den folgenden Befehl aus:
mix test
Sie sollten die Ausgabe ähnlich wie folgt sehen:
Generated chat app
.....
Finished in 0.02 seconds (0.02s async, 0.00s sync)
5 tests, 0 failures
Randomized with seed 84184Jetzt, da wir bestätigt haben, dass alles funktioniert (alle Tests bestehen), gehen wir weiter zum interessanten Teil!
Generieren Sie den (WebSocket) Kanal, der in der Chat -App verwendet werden soll:
mix phx.gen.channel RoomWenn Sie aufgefordert werden, die Installation eines neuen Socket -Handlers Typ
yzu bestätigen und die Taste[Enter]zu drücken.
Dadurch werden drei Dateien erstellt:
* creating lib/chat_web/channels/room_channel.ex
* creating test/chat_web/channels/room_channel_test.exs
* creating test/support/channel_case.exZusätzlich zum Erstellen von zwei weiteren Dateien :
* creating lib/chat_web/channels/user_socket.ex
* creating assets/js/user_socket.js In der Datei room_channel.ex wird empfangen/gesendet, und die grundlegende Interaktion mit dem room_channel_test.exs testet die grundlegende Interaktion mit dem Kanal. Wir konzentrieren uns auf die danach erstellten socket -Dateien. ( Mach dir noch keine Sorgen, wir werden uns die Testdatei in Schritt 14 unten ansehen !)
Wir sind informiert, dass wir einen Code in unserer App aktualisieren müssen:
Add the socket handler to your ` lib/chat_web/endpoint.ex ` , for example:
socket " /socket " , ChatWeb.UserSocket,
websocket: true,
longpoll: false
For the front-end integration, you need to import the ` user_socket.js `
in your ` assets/js/app.js ` file:
import " ./user_socket.js " Der Generator fordert uns auf, den Client -Code in den Frontend zu importieren. Lass uns das später machen. Öffnen Sie vorerst die Datei lib/chat_web/endpoint.ex und befolgen Sie die Anweisungen.
Öffnen Sie danach die Datei mit dem Namen /lib/chat_web/channels/user_socket.ex
und ändern Sie die Linie:
channel "room:*" , ChatWeb.RoomChannelZu:
channel "room:lobby" , ChatWeb.RoomChannelÜberprüfen Sie die Änderung hier.
Dadurch wird sichergestellt, dass alle Nachrichten, die an "room:lobby" gesendet werden, zu unserem RoomChannel weitergeleitet werden.
"room" vorherige "room.*
Weitere Details zu Phoenix -Kanälen ( wir empfehlen Ihnen dringend ) lesen Sie: https://hexdocs.pm/phoenix/channels.html
Öffnen Sie die /lib/chat_web/controllers/page_html/home.html.heex -Datei
und kopieren Sie den folgenden Code:
<!-- The list of messages will appear here: -->
< div class =" mt-[4rem] " >
< ul id =" msg-list " phx-update =" append " class =" pa-1 " > </ ul >
</ div >
< footer class =" bg-slate-800 p-2 h-[3rem] fixed bottom-0 w-full flex justify-center " >
< div class =" w-full flex flex-row items-center text-gray-700 focus:outline-none font-normal " >
< input type =" text " id =" name " placeholder =" Name " required
class =" grow-0 w-1/6 px-1.5 py-1.5 " />
< input type =" text " id =" msg " placeholder =" Your message " required
class =" grow w-2/3 mx-1 px-2 py-1.5 " />
< button id =" send " class =" text-white bold rounded px-3 py-1.5 w-fit
transition-colors duration-150 bg-sky-500 hover:bg-sky-600 " >
Send
</ button >
</ div >
</ footer > Dies ist das grundlegende Formular, mit dem wir Chat -Nachrichten eingeben werden.
Die Klassen, z. w-full und items-center sind TailwindCSS -Klassen, um die Form zu stylen .
Phoenix enthält standardmäßig Tailwind, sodass Sie mit Ihrer App/Idee/"MVP" auf und ablaufen können!
Wenn Sie neu bei
Tailwindsind, siehe: Dwyl/ Learn-TailwindWenn Sie Fragen zu einem der verwendeten
Tailwindhaben, verbringen Sie bitte 2 Minuten damit, die offiziellen (hervorragenden!) Dokumente: Tailwindcss.com/docs zu suchen. Wenn Sie dann noch festsitzen, öffnen Sie bitte ein Problem.
Ihre home.html.heex -Vorlagendatei sollte so aussehen: /lib/chat_web/controllers/page_html/home.html.heex
Öffnen Sie die lib/chat_web/components/layouts/root.html.heex -Datei und suchen Sie das <body> Tag. Ersetzen Sie den Inhalt des <body> durch den folgenden Code:
< body class =" bg-white antialiased min-h-screen flex flex-col " >
< header class =" bg-slate-800 w-full h-[4rem] top-0 fixed flex flex-col justify-center z-10 " >
< div class =" flex flex-row justify-center items-center " >
< h1 class =" w-4/5 md:text-3xl text-center font-mono text-white " >
Phoenix Chat Example
</ h1 >
</ div >
</ header >
< %= @inner_content % >
</ body > Ihre root.html.heex -Vorlagendatei sollte so aussehen: /lib/chat_web/components/layouts/root.html.heex
Wenn Sie am Ende dieses Schritts den Phoenix Server mix phx.server ausführen und die App in Ihrem Browser anzeigen, sieht dies so aus:

Es sieht also bereits wie eine einfache Chat -App aus. Leider schlägt jetzt die Kopie der home.html.heex unsere page_controller_test.exs fehl:
Führen Sie den Befehl aus:
mix test 1) test GET / (ChatWeb.PageControllerTest)
test/chat_web/controllers/page_controller_test.exs:4
Assertion with =~ failed
code: assert html_response(conn, 200) =~ "Peace of mind from prototype to production"
Zum Glück ist das leicht zu reparieren.
page_controller_test.exs Öffnen Sie die Datei test/chat_web/controllers/page_controller_test.exs und ersetzen Sie die Zeile:
assert html_response ( conn , 200 ) =~ "Peace of mind from prototype to production"Mit:
assert html_response ( conn , 200 ) =~ "Phoenix Chat Example"Wenn Sie nun die Tests erneut durchführen, werden sie bestehen:
mix test
Beispielausgabe:
........
Finished in 0.1 seconds (0.09s async, 0.06s sync)
8 tests, 0 failures
Randomized with seed 275786
Open assets/js/app.js , Komponent und ändern Sie die Linie:
import socket from "./user_socket.js" Mit der konkurrierenden Zeile importiert unsere App die Datei socket.js , die uns Websocket -Funktionalität bietet.
Fügen Sie dann den folgenden JavaScript -Code ("Client") zum Ende der Datei hinzu:
/* Message list code */
const ul = document . getElementById ( 'msg-list' ) ; // list of messages.
const name = document . getElementById ( 'name' ) ; // name of message sender
const msg = document . getElementById ( 'msg' ) ; // message input field
const send = document . getElementById ( 'send' ) ; // send button
const channel = socket . channel ( 'room:lobby' , { } ) ; // connect to chat "room"
channel . join ( ) ; // join the channel.
// Listening to 'shout' events
channel . on ( 'shout' , function ( payload ) {
render_message ( payload )
} ) ;
// Send the message to the server on "shout" channel
function sendMessage ( ) {
channel . push ( 'shout' , {
name : name . value || "guest" , // get value of "name" of person sending the message. Set guest as default
message : msg . value , // get message text (value) from msg input field.
inserted_at : new Date ( ) // date + time of when the message was sent
} ) ;
msg . value = '' ; // reset the message input field for next message.
window . scrollTo ( 0 , document . documentElement . scrollHeight ) // scroll to the end of the page on send
}
// Render the message with Tailwind styles
function render_message ( payload ) {
const li = document . createElement ( "li" ) ; // create new list item DOM element
// Message HTML with Tailwind CSS Classes for layout/style:
li . innerHTML = `
<div class="flex flex-row w-[95%] mx-2 border-b-[1px] border-slate-300 py-2">
<div class="text-left w-1/5 font-semibold text-slate-800 break-words">
${ payload . name }
<div class="text-xs mr-1">
<span class="font-thin"> ${ formatDate ( payload . inserted_at ) } </span>
<span> ${ formatTime ( payload . inserted_at ) } </span>
</div>
</div>
<div class="flex w-3/5 mx-1 grow">
${ payload . message }
</div>
</div>
`
// Append to list
ul . appendChild ( li ) ;
}
// Listen for the [Enter] keypress event to send a message:
msg . addEventListener ( 'keypress' , function ( event ) {
if ( event . key === `Enter` && msg . value . length > 0 ) { // don't sent empty msg.
sendMessage ( )
}
} ) ;
// On "Send" button press
send . addEventListener ( 'click' , function ( event ) {
if ( msg . value . length > 0 ) { // don't sent empty msg.
sendMessage ( )
}
} ) ;
// Date formatting
function formatDate ( datetime ) {
const m = new Date ( datetime ) ;
return m . getUTCFullYear ( ) + "/"
+ ( "0" + ( m . getUTCMonth ( ) + 1 ) ) . slice ( - 2 ) + "/"
+ ( "0" + m . getUTCDate ( ) ) . slice ( - 2 ) ;
}
// Time formatting
function formatTime ( datetime ) {
const m = new Date ( datetime ) ;
return ( "0" + m . getUTCHours ( ) ) . slice ( - 2 ) + ":"
+ ( "0" + m . getUTCMinutes ( ) ) . slice ( - 2 ) + ":"
+ ( "0" + m . getUTCSeconds ( ) ) . slice ( - 2 ) ;
}Nehmen Sie sich einen Moment Zeit, um den JavaScript -Code zu lesen und Ihr Verständnis dafür zu bestätigen, was er tut.
Hoffentlich sind die Inline-Kommentare selbsterklärend, aber wenn etwas unklar ist, fragen Sie bitte!
Zu diesem Zeitpunkt sollte Ihre app.js -Datei so aussehen: /assets/js/app.js
user_socket.js Standardmäßig abonniert der Phoenix -Kanal (Client) den generischen Raum: "topic:subtopic" . Da wir dies nicht verwenden, können wir es vermeiden "unable to join: unmatched topic" Fehler in unserem Browser/unserer Konsole zu sehen, indem wir einfach ein paar Zeilen in der Datei user_socket.js ausgeben. Öffnen Sie die Datei in Ihrem Editor und suchen Sie die folgenden Zeilen:
let channel = socket . channel ( "room:42" , { } )
channel . join ( )
. receive ( "ok" , resp => { console . log ( "Joined successfully" , resp ) } )
. receive ( "error" , resp => { console . log ( "Unable to join" , resp ) } )Kommentieren Sie die Zeilen, damit sie nicht ausgeführt werden:
//let channel = socket.channel("room:42", {})
//channel.join()
// .receive("ok", resp => { console.log("Joined successfully", resp) })
// .receive("error", resp => { console.log("Unable to join", resp) }) Ihr user_socket.js sollte jetzt so aussehen: /assets/js/user_socket.js
Wenn Sie sich später entscheiden, Ihre Chat -App aufzuräumen, können Sie diese kommentierten Zeilen aus der Datei
delete.
Wir behalten sie nur als Referenz, wie Sie Kanäle verbinden und Nachrichten empfangen können.
Wenn Sie die App ausführen, füllen Sie die name und die message aus und klicken Sie auf Enter (oder drücken Sie Send ).
Die Nachricht sollte unter verschiedenen Fenstern angezeigt werden!

Damit können wir fortfahren.
Wenn wir den Chat -History nicht speichern wollten , könnten wir diese App sofort bereitstellen und wir würden fertig sein!
In der Tat könnte es eine " Anwendungs-Case "/"" -Funktion "sein, um" Ephemeral "-Chat ohne Geschichte zu führen ... siehe: http://www.pstchat.com/.
Wir gehen jedoch davon aus , dass die meisten Chat -Apps die Geschichte retten, damit
newLeute, die sich dem "Kanal" anschließen, die Geschichte sehen können und Menschen, die kurz "abwesend" sind, die Geschichte "einholen" können.
Führen Sie den folgenden Befehl in Ihrem Terminal aus:
mix phx.gen.schema Message messages name:string message:stringSie sollten die folgende Ausgabe sehen:
* creating lib/chat/message.ex
* creating priv/repo/migrations/20230203114114_create_messages.exs
Remember to update your repository by running migrations:
$ mix ecto.migrateLassen Sie uns diesen Befehl für Klarheit aufschlüsseln:
mix phx.gen.schema - Der Befehl mix zum Erstellen eines neuen Schemas (Datenbanktabelle)Message - Der einzigartige Name für den Aufzeichnung in unseren Nachrichten "Sammlung"messages - Der Name der Sammlung ( oder Datenbanktabelle )name:string - Der Name der Person, die eine Nachricht sendet, die als string gespeichert ist.message:string - Die von der Person gesendete Nachricht, ebenfalls als string gespeichert. Die Zeile creating lib/chat/message.ex erstellt das "Schema" für unsere Nachrichtendatenbanktabelle.
Zusätzlich wird eine Migrationsdatei erstellt, z. B. creating priv/repo/migrations/20230203114114_create_messages.exs Die " Migration " erstellt tatsächlich die Datenbanktabelle in unserer Datenbank.
Führen Sie in Ihrem Terminal den folgenden Befehl aus, um die messages zu erstellen:
mix ecto.migrateFür den Kontext empfehlen wir Lesen: hexdocs.pm/ecto_sql/ Ecto.Migration .html
Sie sollten Folgendes in Ihrem Terminal sehen:
11:42:10.130 [info] == Running 20230203114114 Chat.Repo.Migrations.CreateMessages.change/0 forward
11:42:10.137 [info] create table messages
11:42:10.144 [info] == Migrated 20230203114114 in 0.0s Wenn Sie Ihre PostgreSQL -GUI ( z. B.: pgadmin ) öffnen, werden Sie feststellen, dass die Meldungstabelle in der Datenbank chat_dev erstellt wurde:

Sie können das Tabellenschema mit der rechten Maustaste ( ctrl + click auf Mac ) in der messages anzeigen und "Eigenschaften" auswählen:

Hinweis : Für die Abschnitte 7, 8 und 9 werden wir herausfinden, wie unser Code die verschiedenen Ereignisse, die in unserer Chat -App stattfinden können, "umgehen".
Phoenix abtrkt einen Großteil der zugrunde liegenden Logik für Nachrichtenpassing in der Prozesskommunikation von Elixir ab (weitere Informationen darüber, wie Elixir-Prozesse kommunizieren, hier lesen).
In Phoenix werden vom Client gesendete Ereignisse/Nachrichten automatisch an die entsprechenden Handlerfunktionen auf der Grundlage des Ereignisnamens weitergeleitet, wodurch der Meldung nahtlos und unkompliziert wird!.
Öffnen Sie die Datei lib/chat_web/channels/room_channel.ex und in der Funktion def handle_in("shout", payload, socket) do die folgende Zeile hinzu:
Chat.Message . changeset ( % Chat.Message { } , payload ) |> Chat.Repo . insert So dass Ihre Funktion so aussieht:
def handle_in ( "shout" , payload , socket ) do
Chat.Message . changeset ( % Chat.Message { } , payload ) |> Chat.Repo . insert
broadcast socket , "shout" , payload
{ :noreply , socket }
end Wenn Sie früher bemerkt haben, haben wir in unserer Datei assets/js/app.js die Funktion sendMessage() verwendet, um unsere Nachricht auf das Server auf dem Ereignis "Shout" zu bringen .
Phoenix leitet die Nachricht an die serverseitige handle_in("shout", payload, socket) weiter, da der Ereignisname mit dem 'Shout' übereinstimmt.
In dieser Funktion verarbeiten wir die Nutzlast (die der Nachrichtentext und alle anderen Daten sind) und fügen sie in unsere Datenbank ein. Sauber!
Öffnen Sie die Datei lib/chat/message.ex und Ecto.Query :
defmodule Chat.Message do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query # add Ecto.Query
Fügen Sie dann eine neue Funktion hinzu:
def get_messages ( limit \ 20 ) do
Chat.Message
|> limit ( ^ limit )
|> order_by ( desc: :inserted_at )
|> Chat.Repo . all ( )
end Diese Funktion akzeptiert eine einzelne limit , um nur eine feste/maximale Anzahl von Datensätzen zurückzugeben. Es verwendet die ECTO all , um alle Datensätze aus der Datenbank abzurufen. Message ist der Name des Schemas/der Tabelle, für das wir Datensätze abrufen möchten, und die Grenze ist die maximale Anzahl von Datensätzen, die abgerufen werden sollen.
In der Datei /lib/chat_web/channels/room_channel.ex erstellen Sie eine neue Funktion:
@ impl true
def handle_info ( :after_join , socket ) do
Chat.Message . get_messages ( )
|> Enum . reverse ( ) # revers to display the latest message at the bottom of the page
|> Enum . each ( fn msg -> push ( socket , "shout" , % {
name: msg . name ,
message: msg . message ,
inserted_at: msg . inserted_at ,
} ) end )
{ :noreply , socket } # :noreply
end und oben in der Datei aktualisieren Sie die join -Funktion auf Folgendes:
def join ( "room:lobby" , payload , socket ) do
if authorized? ( payload ) do
send ( self ( ) , :after_join )
{ :ok , socket }
else
{ :error , % { reason: "unauthorized" } }
end
endHinweis : Wie in Abschnitt 7 weiß Phoenix diese Funktion, wenn der Server die interne Nachricht sendet
:after_joinüber den Kanalprozess.Unsere
join/3-Funktion inlib/chat_web/channels/room_channel.exsendet diese:after_join messagean den Kanalprozess, wenn der Client erfolgreich mit dem Thema"room:lobby"eine Verbindung herstellt.
Starten Sie den Phoenix -Server ( wenn er noch nicht ausgeführt wird ):
mix phx.serverHinweis : Die Kompilierung dauert einige Sekunden .
In Ihrem Terminal sollten Sie sehen:
[info] Running ChatWeb.Endpoint with cowboy 2.8.0 at 0.0.0.0:4000 (http)
[info] Access ChatWeb.Endpoint at http://localhost:4000
webpack is watching the files… Dies sagt uns, dass unser Code ( wie erwartet ) und die Chat -App auf TCP Port 4000 ausgeführt wird!
Öffnen Sie die Chat -Web -App in zwei separaten Browser -Windows : http: // localhost: 4000
( Wenn Ihr Computer nur einen Browser hat, verwenden Sie eine Registerkarte "Incognito" )
Sie sollten in der Lage sein, Nachrichten zwischen den beiden Browserfenstern zu senden: 
Glückwunsch! Sie haben eine funktionierende ( grundlegende ) Chat -App in Phoenix geschrieben!
Der Chat (Nachricht) wird gespeichert !
Dies bedeutet, dass Sie den Browser aktualisieren oder sich einem anderen Browser anschließen können und die Geschichte immer noch sehen werden!
Automatische Tests sind eine der besten Möglichkeiten, um die Zuverlässigkeit in Ihren Webanwendungen zu gewährleisten.
HINWEIS : Wenn Sie bei automatisierten Tests oder "testgetriebenen Entwicklung" ("TDD") vollständig neu sind, empfehlen wir, das Tutorial "Basic" zu lesen/zu folgen: github.com/dwyl/ Learn-tdd
Das Testen in Phoenix ist schnell ( Tests parallel laufen! ) Und leicht zu beginnen! Das ExUnit -Test-Framework ist integriert, sodass es keine "Entscheidungen/Debatten" darüber gibt, welches Framework oder welchen Stil verwendet werden soll.
Wenn Sie einen Test mit ExUnit noch nie gesehen oder geschrieben haben, sollten Sie sich keine Angst vorstellen, die Syntax sollte bekannt sein, wenn Sie in der Vergangenheit einen automatisierten Test geschrieben haben.
Wenn Sie eine neue Phoenix -App erstellen oder eine neue Funktion ( wie ein Kanal ) hinzufügen, generiert Phoenix einen neuen Test für Sie.
Wir führen die Tests mit dem Befehl mix test aus:
... ... ..
Finished in 0.1 seconds ( 0.05 s async , 0.06 s sync )
8 tests , 0 failures
Randomized with seed 157426In diesem Fall schlägt keiner dieser Tests fehl. ( 8 Tests, 0 Fehler )
Es lohnt sich, sich einen Moment Zeit zu nehmen ( oder so lange wie Sie brauchen !) Zu verstehen, was in der Datei /room_channel_test.exs vor sich geht. Öffnen Sie es, wenn Sie es noch nicht getan haben. Lesen Sie die Testbeschreibungen und den Code.
Für ein bisschen Kontext empfehlen wir Lesen: https://hexdocs.pm/phoenix/ testing_channels .html
Schauen wir uns den ersten Test in /test/chat_web/channels/room_channel_test.exs an:
test "ping replies with status ok" , % { socket: socket } do
ref = push socket , "ping" , % { "hello" => "there" }
assert_reply ref , :ok , % { "hello" => "there" }
end Der Test erhält den socket aus der setup -Funktion ( in Zeile 6 der Datei ) und weist das Ergebnis des Aufrufens der push -Funktion einer Variablen ref push -PUSH -PUSH -PUSH -PUSH ( MAP %{"hello" => "there"} ) auf den socket zum Thema "ping" zu.
Die Funktion " handle_in ", die das Thema "ping" behandelt:
def handle_in ( "ping" , payload , socket ) do
{ :reply , { :ok , payload } , socket }
end Antworten einfach mit der Nutzlast, die Sie senden. Daher können wir in unserem Test das assert_reply -Makro verwenden, um zu behaupten, dass der ref gleich :ok, %{"hello" => "there"}
Hinweis : Wenn Sie Fragen haben oder Hilfe benötigen, um die anderen Tests zu verstehen, öffnen Sie bitte ein Problem auf GitHub, wir erweitern dies weiter!
( Wir versuchen nur, dieses Tutorial angemessen "kurz" zu halten, damit Anfänger von irgendetwas nicht "überwältigt" sind ...)
Oft können wir viel über eine Anwendung ( oder API ) lernen, wenn wir die Tests lesen und sehen, wo sich die "Lücken" der Tests befinden.
Zum Glück können wir dies mit nur wenigen Schritten erreichen:
mix.exs excoveralls hinzufügen Öffnen Sie Ihre mix.exs -Datei und finden Sie die Funktion "DEPs":
defp deps do
Fügen Sie ein Komma zum Ende der letzten Zeile hinzu und fügen Sie dann die folgende Zeile zum Ende der Liste hinzu:
{ :excoveralls , "~> 0.15.2" , only: [ :test , :dev ] } # tracking test coverage Suchen Sie außerdem den Abschnitt def project do ( nach mix.exs ) und fügen Sie der Liste die folgenden Zeilen hinzu:
test_coverage : [ tool : E xCoveralls ] ,
preferred_cli_env: [
coveralls : :test ,
"coveralls.detail": :test ,
"coveralls.post": :test ,
"coveralls.html": :test
] Installieren Sie dann die Abhängigkeit von excoveralls , die wir gerade zu mix.exs hinzugefügt haben:
mix deps.getSie sollten sehen:
Resolving Hex dependencies...
Dependency resolution completed:
* Getting excoveralls (Hex package)
... etc.coveralls.json Erstellen Sie im "Root" ( Basisverzeichnis ) des Chat-Projekts eine neue Datei namens coveralls.json und kopieren Sie Folgendes:
{
"coverage_options" : {
"minimum_coverage" : 100
},
"skip_files" : [
" test/ " ,
" lib/chat/application.ex " ,
" lib/chat_web.ex " ,
" lib/chat_web/telemetry.ex " ,
" lib/chat_web/components/core_components.ex " ,
" lib/chat_web/channels/user_socket.ex "
]
}
Diese Datei ist sehr einfach, sie weist die coveralls -App an, eine minimum_coverage von 100% ( dh alles zu testen 1 ) und die Dateien im test/ Verzeichnis für die Überprüfung der Abdeckung zu ignorieren . Wir ignorieren auch Dateien wie application.ex , telemetry.ex , core_components.ex und user_socket.ex da sie für die Funktionalität unseres Projekts nicht relevant sind.
1 Wir glauben, dass es sich lohnt, später ein wenig Zeit im Voraus zu investieren , um Tests für all unseren Code zu schreiben, um später weniger Fehler zu haben.
Fehler sind teuer , die Tests sind billig und Vertrauen / Zuverlässigkeit ist von unschätzbarem Wert .
Um die Tests mit Abdeckung durchzuführen, kopieren Sie den folgenden Befehl in Ihr Terminal:
MIX_ENV = test mix do coveralls . json
Für die Verwendung von Windows:
$ env :MIX_ENV = "test" ; mix do coveralls . json
Sie sollten sehen:
Randomized with seed 527109
----------------
COV FILE LINES RELEVANT MISSED
100.0% lib/chat.ex 9 0 0
100.0% lib/chat/message.ex 26 4 0
100.0% lib/chat/repo.ex 5 0 0
70.0% lib/chat_web/channels/room_channel.ex 46 10 3
100.0% lib/chat_web/components/layouts.ex 5 0 0
100.0% lib/chat_web/controllers/error_html.ex 19 1 0
100.0% lib/chat_web/controllers/error_json.ex 15 1 0
100.0% lib/chat_web/controllers/page_controller 9 1 0
100.0% lib/chat_web/controllers/page_html.ex 5 0 0
100.0% lib/chat_web/endpoint.ex 49 0 0
66.7% lib/chat_web/router.ex 27 3 1
[TOTAL] 80.0%
----------------
Wie wir hier können, werden nur 80% der Codezeilen in /lib durch die von uns geschriebenen Tests "abgedeckt".
Um die Berichterstattung in einem Webbrowser anzuzeigen, führen Sie Folgendes aus:
MIX_ENV = test mix coveralls . html ; open cover / excoveralls . html Dadurch wird der Deckungsbericht (HTML) in Ihrem Standard -Webbrowser geöffnet:

Öffnen Sie die Datei test/chat_web/channels/room_channel_test.exs und fügen Sie den folgenden Test hinzu:
test ":after_join sends all existing messages" , % { socket: socket } do
# insert a new message to send in the :after_join
payload = % { name: "Alex" , message: "test" }
Chat.Message . changeset ( % Chat.Message { } , payload ) |> Chat.Repo . insert ( )
{ :ok , _ , socket2 } = ChatWeb.UserSocket
|> socket ( "person_id" , % { some: :assign } )
|> subscribe_and_join ( ChatWeb.RoomChannel , "room:lobby" )
assert socket2 . join_ref != socket . join_ref
end Schließlich kommentieren Sie in lib/chat_web/router.ex das folgende Code.
pipeline :api do
plug :accepts , [ "json" ]
end Da wir dies nicht verwenden :api in diesem Projekt, müssen es nicht testen.
Wenn Sie nun MIX_ENV=test mix do coveralls.json , dass Sie sehen sollten:
Randomized with seed 15920
----------------
COV FILE LINES RELEVANT MISSED
100.0% lib/chat.ex 9 0 0
100.0% lib/chat/message.ex 26 4 0
100.0% lib/chat/repo.ex 5 0 0
100.0% lib/chat_web/channels/room_channel.ex 46 10 0
100.0% lib/chat_web/components/layouts.ex 5 0 0
100.0% lib/chat_web/controllers/error_html.ex 19 1 0
100.0% lib/chat_web/controllers/error_json.ex 15 1 0
100.0% lib/chat_web/controllers/page_controller 9 1 0
100.0% lib/chat_web/controllers/page_html.ex 5 0 0
100.0% lib/chat_web/endpoint.ex 49 0 0
100.0% lib/chat_web/router.ex 27 2 0
[TOTAL] 100.0%
----------------
Dieser Test erstellt nur eine Nachricht vor dem subscribe_and_join , sodass in der Datenbank eine Nachricht an einem Clien -Verbindungssend in der Chat vorliegt.
Auf diese Weise hat das :after_join mindestens eine Nachricht und der Enum.each .
Damit ist unsere App vollständig getestet!
Wir können dieses Projekt erweitern , um die grundlegende Authentifizierung zu unterstützen. Wenn Sie verstehen möchten, wie Authentifizierung implementiert wird, siehe: Auth.md
Presence hinzufügen, um zu verfolgen, wer online ist Einer der großen Vorteile bei der Verwendung Phoenix ist, dass Sie problemlos Prozesse und Kanäle verfolgen können.
Dies ebnet den Weg, um mühelos zu zeigen, wer online ist oder nicht!
Wenn Sie daran interessiert sind, diese Funktion zu entwickeln, haben wir in presence.md einen Leitfaden erstellt.md nur für Sie! ?
Durch kontinuierliche Integration können Sie die Tests automatisieren, um zu überprüfen, ob Ihre App wie erwartet funktioniert ( vor der Bereitstellung ). Dies verhindert versehentlich Ihre App " zu brechen ".
Zum Glück sind die Schritte recht einfach.
Zum Beispiel ci.yml siehe:
.github/workflows/ci.yml
Der Einsatz zu fly.io dauert ein paar Minuten. Wir empfehlen dem offiziellen Leitfaden: fly.io/docs/elixir/
Sobald Sie bereitgestellt haben, können Sie Ihre App in jedem Web-/Mobile -Browser anzeigen/verwenden.
zB: phoenix-chat .fly.dev/

Wenn Sie dieses Beispiel nützlich fanden, wissen Sie bitte das Github -Repository, damit wir ( und andere ) es Ihnen gefallen haben!
Wenn Sie mehr Phoenix und die Magie von LiveView erfahren möchten, lesen Sie das Tutorial in unserem Anfänger: github.com/dwyl/ Phoenix-liveview-counter-tutorial
Für eine Version einer Chat-Anwendung mit LiveView können Sie das folgende Repository lesen: github.com/dwyl/ phoenix-liveview-chat-plample
Vielen Dank, dass Sie mit uns gelernt haben! ☀️
Dieses Repo ist von @chrismccords einfachem Chat -Beispiel inspiriert: https://github.com/chrismccord/phoenix_chat_example ❤️
Zum Zeitpunkt des Schreibens wurde Chris 'Beispiel zuletzt am 20. Februar 2018 aktualisiert und verwendet Phoenix 1.3: Ausgaben/40.
Es gibt einige Unterschiede (Veränderungen) zwischen Phoenix 1.3 und 1.6 ( der neuesten Version ).
In unserem Tutorial wird Phoenix 1.6.2 (neueste zum letzten Oktober 2021) verwendet. Wir hoffen, dass wir durch das Schreiben ( und Pflege ) ein Schritt-für-Schritt-Fokussierungstutorial zur Elixir/Phoenix-Community beitragen, ohne PRS auf Chris 'Repo zu häufen.