Så här använder du Faye som en realtids push server i Rails

Det finns flera sätt att lägga till push-funktionalitet till en applikation, inklusive Pushr och Pub-Nub, som är ganska eleganta och enkla lösningar. Det finns också några mer avancerade alternativ. I den här artikeln ska jag visa dig hur du använder Faye, ett meddelandesystem som körs på både Ruby och Node.js.


Steg 1 - Få allt klart

Vi ska bygga en enkel chattjänst. Nu täckte Ryan Bates detta på Railscast # 260, men vi kommer att ta en något annorlunda inställning i denna handledning. Först ska vi skapa en chattjänst där användarna går in i ett offentligt rum, och alla kan chatta med varandra offentligt. Den andra funktionaliteten vi lägger till är privata meddelanden. Dessutom integrerar vi viss säkerhet i vår implementering med hjälp av Ryan Bates private_pub pärla.

Var säker på att du har en arbetsinställning av Ruby och Ruby on Rails 3.1. Bortsett från det, behöver du tunt. Thin är en mycket använd Ruby webserver, och Faye kräver att den körs (den fungerar inte med WEBrick, Rails inbyggda server). Du kan installera Tunn, som så:

pärla installerad tunn

Vi borde vara alla, så låt oss skapa ansökan:

skenar ny faye-handledning

Lägg nu till faye pärla till din Gemfile:

 pärla "faye"

och springa buntinstallation att installera det. Faye behöver springa på en separat webbserver från webbapplikationen själv; För att uppnå detta måste du skapa en Rackup config-fil. Lägg till en faye.ru filen till projektets rot och se till att det ser ut så här:

 kräver "faye" bayeux = Faye :: RackAdapter.new (: mount => '/ faye',: timeout => 25) bayeux.listen (9292)

Den här filen berättar bara Rackup hur man startar Faye-servern. Prova det för att se till att det fungerar korrekt. Kör detta i din terminal:

rackup faye.ru -E-produktion är tunn

Om du inte får några fel, är du bra att gå!


Steg 2 - Några grundläggande autentiseringar

För att skapa en chattprogram behöver vi två grundläggande saker: användare och ett chattrum. Vi kommer inte att verifiera våra användare, men vi behöver fortfarande ge dem ett sätt att ange deras användarnamn. Låt oss skapa det. Kör följande kommando för att skapa en session kontrollant så vi kan logga in dem:

skenor g kontroll sessioner nya skapa

Detta kommer att skapa en sessioner kontrollant och två metoder: ny och skapa. Lägg till dessa rutter till din routes.rb fil:

 få '/ login' => 'sessioner # nya',: som =>: inloggningsplattform '/ login' => 'sessioner # skapa',: som =>: inloggning

Dessa två vägar bör vara självförklarande för dig. Gå vidare och ändra app / vyer / sessions / new.html.erb fil:

 <%= form_tag login_path do |f| %> <%= label_tag :username %> <%= text_field_tag :username %> <%= submit_tag "Enter" %> <% end %>

Och ha skapa metod inom sessionerna kontrollant ser ut som följande:

 def skapa session [: användarnamn] = params [: användarnamn] render: text => "Välkommen # session [: användarnamn]!" slutet

Fortsätt prova det! Springa rails server i terminalen och peka din webbläsare till localhost: 3000 / login och ange ett användarnamn. Du bör hälsas med din ansökan efter att du skickat in formuläret.

Om du är ute efter en utmaning kan du använda Omniauth för att lägga till Twitter eller Facebook-integration för detta steg!


Steg 3 - Chattrummet

Nu när vi har grundläggande autentisering, låt oss lägga till ett chattrum. Kör följande kommando för att skapa en chatt kontrollant:

skenor genererar controller chattrum

Detta kommer att generera våra chattar kontrollant och en rum metod. Vi måste lägga till några rutter för att göra vårt chattarbete, så lägg till den här raden till din routes.rb fil:

 få '/ chatroom' => 'chattar # rum',: som =>: chatt

Denna rutt leder vår användare till chattrummet och låter dem skicka meddelanden via en enkel blankett. Ändra rum metod på chattarna kontrollant och få det att se ut så här:

 def room redirect_ till login_path om inte session [: användarnamn] slutar

Detta kommer att se till att användarna anger ett användarnamn om de vill chatta. Nu, låt oss skapa rummet själv! Lägg till det här i app / vyer / chatt / room.html.erb:

 

Välkommen till chattrummet <%= session[:username] %>!

Detta är en enkel struktur för rummet. Blanketten i slutet kommer att hanteras av någon JavaScript-kod som publicerar meddelandet till chattrummet.

Nu, för att skicka meddelanden till rummet, måste vi lägga till några JavaScript i vår vy. Lägg först till Fayes bibliotek till app / vyer / layouter / application.html.erb:

 <%= javascript_include_tag "http://localhost:9292/faye.js" %>

Lägg sedan till följande i början av room.html.erb se:

 

Den här metoden tar meddelandet i den form som vi lagt till tidigare (när den skickas in) och skickar författarens användarnamn och meddelande till "/ meddelanden / offentliga" -kanalen i ett JSON-objekt. Kanaler är Fayes sätt att skicka meddelanden. En användare abonnerar på en kanal och tar emot alla meddelanden som skickas till den. I vårt fall finns det bara en kanal, som är den offentliga. Låt oss dissekera koden lite mer:

  1. Först instämmer vi en ny Faye-klient och har den ansluten till vår Faye-server.
  2. Därefter hanterar vi formulärets inlämning. När användaren träffar inmatningsnyckeln eller klickar "Skicka" publicerar vi det tidigare nämnda JSON-objektet som innehåller meddelandets avsändare och meddelandet själv till den offentliga kanalen.
  3. Därefter rensar vi meddelandeboxen och returnera falskt, för att undvika att formuläret faktiskt lämnas in och uppdaterar sidan.

Nu publicerar detta meddelanden till chattrummet, men våra anslutna användare kan inte ta emot dem, eftersom deras webbläsare inte prenumererar på kanalen. Detta uppnås genom lite mer JavaScript. Gör JavaScript-blocket på app / vyer / chatt / room.html.erb ser ut så här:

 

Detta ansluter helt enkelt till Fayes server och prenumererar på "/ meddelanden / offentliga" -kanalen. Den återuppringning vi tillhandahåller tar emot de skickade meddelandena. data kommer att vara det JSON-objekt som vi publicerade tidigare, så vi använder helt enkelt det för att skapa en tagga med meddelandet inuti, och lägg till det i chattrummets behållare.

Du borde nu ha en enkel chatt! Kör både Faye och Rails-servern och öppna två webbläsare (eller ett Incognito-fönster på Chrome till exempel). Du kan ange två olika användarnamn och testa din chatt. Meddelanden ska visas nästan direkt på chattrummet när du skickat dem.


Steg 4 - Lägga till privata meddelanden

Just nu kan användarna chatta med varandra, men alla meddelanden är offentliga. Låt oss lägga till lite enkel funktionalitet där människor kan skicka privata meddelanden genom att nämna mottagarens användarnamn - som om i Twitter. För att detta ska fungera ska vi prenumerera våra användare på sina egna kanaler, så de är de enda som kan ta emot meddelanden från den. Gör din app / vyer / chatt / room.html.erb JavaScript ser så här ut:

 

Som du kan se abonnerar vi på två Faye-kanaler: den ena är den offentliga kanalen och den andra är en kanal som heter "/ meddelanden / privat / USERNAME" (observera att vi använder användarnamnet i Rails-sessionen). På det sättet, när någon nämner den användaren, istället för att skicka meddelandet via den offentliga kanalen, skickar vi den via mottagarens privata kanal, så bara den personen kan läsa den. Vi lägger också till några enkla stilar till den, så den visas med fetstil.

En annan sak som ändrats är koden som publicerar meddelanden. Vi kontrollerar först om meddelandet är privat, genom att använda ett enkelt regelbundet uttryck som letar efter ett omnämnande. Om det är, publicerar vi ett meddelande till mottagarens specifika kanal. Om inte, gör vi exakt som vi gjorde tidigare - publicera det på den offentliga kanalen.

Nu prova det! Skicka meddelanden till andra användare genom att nämna dem, du borde bara se dem i mottagarens chattfönster.


Steg 5 - Några tillvägagångssätt

Denna implementering har sina brister. Först kontrollerar vi inte om användarnamnet som en person väljer är redan i bruk. Detta skulle innebära att alla kunde skriva in samma användarnamn som någon annan och skicka meddelanden som låtsas vara dem och även få sina privata meddelanden! Detta löses enkelt genom att lägga till ett slags autentiseringssystem eller genom att lagra användarnamnen, som för närvarande används, i en databas. Jag kommer inte att täcka detta i dagens handledning, men det borde vara ganska enkelt för dig att implementera. Om du behöver hjälp, lämna en kommentar, så hjälper vi oss!

Den andra varningen är inte så uppenbar. Problemet med vår implementering är att alla kan manipulera JavaScript i flygningen (med hjälp av Firebug till exempel) för att prenumerera på vilken kanal de vill (även privata kanaler), och de kan publicera meddelanden till dem som låtsas vara någon annan. Det här är inte lika lätt löst som den första fel jag påpekade (om vi skulle lösa detta manuellt), men Ryan Bates skapade en pärla som gör den här uppgiften till en film och vår app är mycket säker.

Ädelstenen heter privat_pub; det förbjuder i huvudsak användaren att publicera till kanaler med JavaScript, vilket innebär att endast Rails-appen kan publicera till dem. Detta lägger till viss säkerhet eftersom en skadlig användare inte skulle kunna publicera till privata kanaler. En annan sak som denna pärla löser är prenumerationer. Med privat_pub kan en användare bara ta emot meddelanden från kanaler vi prenumererar på så att de inte kan lägga till en prenumeration manuellt och lösa hela problemet.

Så låt oss lägga till det i vårt Gemfile:

 pärla 'private_pub',: git => 'git: //github.com/ryanb/private_pub.git'

springa buntinstallation att installera pärlan och köra generatorn för att skapa konfigurationsfilerna:

skenor g private_pub: installera

Du kommer att få en konfliktvarning när du kör det här kommandot (private_pub försöker skriva över faye.ru fil). Skriv bara "Y" och tryck på Enter, eftersom det är nödvändigt att skriva över den filen. Du måste också flytta offentliga / private_pub.js fil till app / tillgångar / javascript mapp. Och det sista: Ta bort linjen som innehåller faye.jsapplication.html.erb, eftersom Private Pub inkluderar det automatiskt. Se till att du startar om båda servrarna (skenor och faye) vid denna tidpunkt.

Nu måste vi göra några ändringar. Först prenumerera en användare på en kanal på olika sätt med privat_pub. Redigera app / vyer / chatt / room.html.erb och lägg till följande före JavaScript-blocket:

 <%= subscribe_to "/messages/public" %> <%= subscribe_to "/messages/private/#session[:username]" %>

Detta är private_pubsätt att prenumerera på kanaler. Detta tillåter användaren att ta emot meddelanden via den kanal du anger. Nu måste vi ändra JavaScript-koden till följande:

PrivatePub.subscribe ("/ messages / public", funktion (data)
$ (''). html (data.username + ":" + data.msg) .appendTo ('# chat_room');
);

PrivatePub.subscribe ( "/ meddelanden / privat /<%= session[:username] %>", funktion (data)
$ (''). addClass ('privat'). html (data.username + ":" + data.msg) .appendTo ('# chat_room');
);

Den enda skillnaden här är att vi använder PrivatePub för att prenumerera på kanaler istället för Faye-biblioteket direkt.

Vi måste också ändra hur vi publicerar meddelanden. Med Private Pub kan endast programmet Rails publicera meddelanden. Javascript-biblioteket kan inte publicera meddelanden på egen hand. Det här är en bra sak, eftersom vi tar full kontroll över vem som publicerar meddelanden och vilken kanal. För att göra detta måste vi ändra formuläret som används för att skicka meddelanden till följande:

 <%= form_tag new_message_path, :remote => sant gör%> <%= text_field_tag :message %> <%= submit_tag "Send" %> <% end %>

Det här är en AJAX-blankett, så det uppdaterar inte sidan när den skickas in. Det kommer också att leta efter new_message_path, så var noga med att du lägger till den här routes.rb:

 posta '/ new_message' => 'chats # new_message',: as =>: new_message

Du behöver också skapa en ny metod på chattkontroller:

 def new_message # Kontrollera om meddelandet är privat om mottagaren = params [: message] .match (/@(.+) (. +) /) # Det är privat, skicka det till mottagarens privata kanal @channel = "/ messages /private/#recipient.captures.first "@message = : username => session [: användarnamn],: msg => recipient.captures.second else # Det är offentligt, så skicka det till den offentliga kanalen @ channel = "/ messages / public" @message = : användarnamn => session [: användarnamn],: msg => params [: message] avsluta svara för att göra | f | f.js änden

Detta fungerar väldigt mycket som dess JavaScript-motsvarighet. Det avgör om meddelandet innehåller ett omnämnande, och om det gör det skickar det meddelandet till mottagarens privata kanal. Om inte, skickar det meddelandet via den offentliga kanalen. Nu skickar detta inte budskapet, det skapar bara två variabler som vi behöver använda från utsikten för att skicka ett. Privat Pub tillåter dig inte att skicka meddelanden via kontrollant (åtminstone inte med den version jag använde för denna handledning), så fortsätt och skapa filen app / vyer / chatt / new_message.js.erb och lägg till följande:

 // Clear message input $ ('# message'). Val ("); // Skicka meddelandet <% publish_to @channel, @message %>

Detta kommer att köra den första raden av kod, rensa meddelandeboxen och ringa publish_to, Privat Pub skickar @meddelande (som kommer att konverteras till ett JSON-objekt när det kommer) till @kanalisera. Enkelt, va?

Fortsätt prova det. Det ska fungera precis som tidigare, bara med ny tillförd säkerhet!


Slutsats

Jag hoppas att den här artikeln gav dig en inblick i hur du använder Faye för dina projekt. Jag rekommenderar att du alltid använder Private Pub, eftersom den lägger till en viktig säkerhetsnivå, om inte du verkligen behöver det.

Om du har några frågor, tveka att fråga dem i kommentarerna eller skicka mig en tweet!