Come utilizzare Faye come server di push in tempo reale in Rails

Esistono diversi modi per aggiungere funzionalità push a un'applicazione, tra cui Pushr e Pub-Nub, soluzioni piuttosto eleganti e semplici. Ci sono anche alcune opzioni più avanzate. In questo articolo, ti mostrerò come usare Faye, un sistema di messaggistica che funziona sia su Ruby che su Node.js.


Passaggio 1: prepara tutto

Stiamo andando a costruire un semplice servizio di chat. Ora, Ryan Bates ha parlato di questo su Railscast # 260, tuttavia, avremo un approccio leggermente diverso in questo tutorial. Innanzitutto, creeremo un servizio di chat in cui gli utenti entrano in una sala pubblica e tutti possono chattare pubblicamente. La seconda funzionalità che aggiungeremo è messaggi privati. Inoltre, integreremo un po 'di sicurezza nella nostra implementazione usando la gemma private_pub di Ryan Bate.

Assicurati di avere una configurazione funzionante di Ruby e Ruby on Rails 3.1. A parte questo, avrai bisogno di magro. Thin è un server Web Ruby ampiamente utilizzato e Faye richiede l'esecuzione (non funziona con WEBrick, il server integrato di Rails). Puoi installare Thin, in questo modo:

gem installazione sottile

Dovremmo essere tutti impostati, quindi creiamo l'applicazione:

rotaie new faye-tutorial

Ora, aggiungi il faye gemma per il tuo Gemfile:

 gemma 'fata'

e corri installazione bundle per installarlo. Faye deve essere eseguito su un server Web separato dall'applicazione Web stessa; per fare ciò, è necessario creare un file di configurazione Rackup. Aggiungere un faye.ru file alla radice del progetto e assicurati che assomigli così:

 richiede 'faye' bayeux = Faye :: RackAdapter.new (: mount => '/ faye',: timeout => 25) bayeux.listen (9292)

Questo file dice semplicemente a Rackup come avviare il server Faye. Provalo per assicurarti che funzioni correttamente. Eseguilo nel tuo terminale:

rackup faye.ru -E produzione -s sottile

Se non ricevi errori, allora sei a posto!


Passaggio 2: alcune Autenticazione di base

Per creare un'applicazione di chat, abbiamo bisogno di due cose fondamentali: gli utenti e una chat room. Non abbiamo intenzione di autenticare i nostri utenti, ma abbiamo ancora bisogno di fornire loro un modo per impostare il loro nome utente. Creiamo quello. Eseguire il seguente comando per creare una sessione controllore quindi possiamo registrarli in:

rails g controller sessions new create

Questo creerà una sessione controllore e due metodi: nuovo e creare. Aggiungi questi percorsi al tuo routes.rb file:

 get '/ login' => 'sessioni # nuovo',: come =>: login post '/ login' => 'sessioni # create',: as =>: login

Queste due vie dovrebbero essere auto-esplicative per te. Vai avanti e modifica il app / views / sessioni / new.html.erb file:

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

E avere il creare metodo all'interno delle sessioni controllore assomiglia al seguente:

 def create session [: username] = params [: username] render: text => "Welcome # session [: username]!" fine

Vai avanti e provalo! Correre rails server nel terminale e indirizzare il browser a localhost: 3000 / login e inserire un nome utente. Dovresti essere accolto dalla tua domanda dopo aver inviato il modulo.

Se sei pronto per una sfida, puoi utilizzare Omniauth per aggiungere un'integrazione a Twitter o Facebook per questo passaggio!


Passaggio 3: la chat room

Ora che abbiamo qualche autenticazione di base, aggiungiamo una chat room. Eseguire il seguente comando per creare una chat controllore:

i binari generano la stanza delle chat del controller

Questo genererà le nostre chat controllore e uno camera metodo. Abbiamo bisogno di aggiungere alcuni percorsi per far funzionare la nostra chat, quindi aggiungi questa linea al tuo routes.rb file:

 get '/ chatroom' => 'chat # room',: as =>: chat

Questo percorso indirizzerà il nostro utente alla chat room e consentirà loro di postare messaggi attraverso un semplice modulo. Modifica il camera metodo sulle chat controllore e farlo sembrare così:

 def room redirect_to login_path a meno che la sessione [: username] termini

Ciò assicurerà che gli utenti impostino un nome utente se desiderano chattare. Ora, creiamo la stanza stessa! Aggiungi questo al app / views / chat / room.html.erb:

 

Benvenuto nella chat room <%= session[:username] %>!

Questa è una struttura semplice per la stanza. Il modulo alla fine sarà gestito da qualche codice JavaScript che pubblicherà il messaggio nella chat room.

Ora, per pubblicare messaggi nella stanza, dobbiamo aggiungere alcuni JavaScript alla nostra vista. Innanzitutto, aggiungi la biblioteca di Faye a app / views / layout / application.html.erb:

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

Quindi, aggiungere quanto segue all'inizio del room.html.erb vista:

 

Questo metodo prende il messaggio nel modulo che abbiamo aggiunto in precedenza (al momento dell'invio) e invia il nome utente e il messaggio dell'autore al canale "/ messages / public" in un oggetto JSON. I canali sono il modo in cui Faye invia i messaggi. Un utente si iscrive a un canale e riceve tutti i messaggi che gli vengono inviati. Nel nostro caso, c'è solo un canale, che è quello pubblico. Analizziamo un po 'il codice:

  1. Per prima cosa istanziamo un nuovo client Faye e lo colleghiamo al nostro server Faye.
  2. Successivamente, gestiamo l'invio del modulo. Quando l'utente preme il tasto Invio o fa clic su "Invia", pubblicheremo il suddetto oggetto JSON contenente il mittente del messaggio e il messaggio stesso al canale pubblico.
  3. Successivamente, cancelliamo la finestra del messaggio e restituisce falso, per evitare che il modulo venga effettivamente inviato e che si aggiorni la pagina.

Ora, questo pubblicherà messaggi nella chat room, ma i nostri utenti connessi non saranno in grado di riceverli, perché i loro browser non sono iscritti al canale. Questo è ottenuto attraverso un po 'più di JavaScript. Attiva il blocco JavaScript app / views / chat / room.html.erb sembra così:

 

Questo si collega semplicemente al server di Faye e si abbona al canale "/ messages / public". Il callback che forniamo riceve i messaggi inviati. dati sarà l'oggetto JSON che abbiamo pubblicato prima, quindi lo usiamo semplicemente per creare un taggalo con il messaggio all'interno e aggiungilo al contenitore della chat room.

Ora dovresti avere una semplice chat! Esegui sia il server Faye che il server Rails e apri due browser (o una finestra di navigazione in incognito su Chrome, ad esempio). Puoi inserire due nomi utente diversi e testare la tua chat. I messaggi dovrebbero apparire quasi istantaneamente nella chat room dopo averli inviati.


Passaggio 4: aggiunta di messaggi privati

Al momento, gli utenti sono in grado di chattare tra loro, ma tutti i messaggi sono pubblici. Aggiungiamo alcune semplici funzionalità in cui le persone possono inviare messaggi privati ​​a qualcuno, citando il nome utente del destinatario, un po 'come in Twitter. Affinché ciò funzioni, abboneremo i nostri utenti ai loro canali, quindi sono gli unici a poter ricevere messaggi da esso. Rendere il vostro app / views / chat / room.html.erb JavaScript assomiglia a questo:

 

Come puoi vedere, ci stiamo iscrivendo a due canali Faye: uno è il canale pubblico, e il secondo è un canale, chiamato "/ messages / private / USERNAME" (nota che usiamo il nome utente nella sessione Rails). In questo modo, quando qualcuno menziona quell'utente, invece di inviare il messaggio attraverso il canale pubblico, lo inviamo attraverso il canale privato del destinatario, quindi solo quella persona può leggerlo. Aggiungiamo anche alcuni stili semplici, quindi viene visualizzato in grassetto.

Un'altra cosa che è cambiata è il codice che pubblica i messaggi. Per prima cosa controlliamo se il messaggio è privato, applicando una semplice espressione regolare che cerca una menzione. Se lo è, pubblichiamo un messaggio sul canale specifico del destinatario. In caso contrario, facciamo esattamente come prima - pubblicalo sul canale pubblico.

Ora provalo! Invia messaggi ad altri utenti citandoli, dovresti visualizzarli solo nella finestra di chat del destinatario.


Passaggio 5: alcuni avvertimenti

Questa implementazione ha i suoi difetti. Innanzitutto, non controlliamo se il nome utente scelto da una persona è già in uso. Ciò significherebbe che chiunque potrebbe immettere lo stesso nome utente di qualcun altro e inviare messaggi fingendo di essere loro, e persino ricevere i loro messaggi privati! Questo è facilmente risolvibile aggiungendo una sorta di sistema di autenticazione o memorizzando i nomi utente, che sono attualmente in uso, all'interno di un database. Non lo coprirò nel tutorial di oggi, ma dovrebbe essere abbastanza facile da implementare. Se hai bisogno di assistenza, lascia un commento e noi ti aiuteremo!

La seconda avvertenza non è così ovvia. Il problema con la nostra implementazione è che chiunque può manipolare il JavaScript al volo (usando Firebug ad esempio) per iscriversi a qualsiasi canale che desidera (anche canali privati), e possono pubblicare messaggi che fingono di essere qualcun altro. Questo non è risolto facilmente come il primo difetto che ho segnalato (se dovessimo risolvere questo manualmente), ma Ryan Bates ha creato un gioiello che rende questa attività un gioco da ragazzi, e la nostra app molto sicura.

La gemma è chiamata private_pub; In sostanza proibisce a qualsiasi utente di pubblicare su canali con JavaScript, cioè solo l'app Rails è in grado di pubblicare su di essi. Ciò aggiunge un po 'di sicurezza poiché un utente malintenzionato non sarebbe in grado di pubblicare su canali privati. Un'altra cosa che questa gemma risolve sono gli abbonamenti. Con private_pub, un utente può ricevere solo messaggi dai canali a cui li abboniamo, quindi non è possibile aggiungere manualmente un abbonamento, risolvendo l'intero problema.

Quindi aggiungiamolo al nostro Gemfile:

 gem 'private_pub',: git => 'git: //github.com/ryanb/private_pub.git'

correre installazione bundle per installare la gemma ed eseguire il generatore per creare i file di configurazione:

rails g private_pub: install

Riceverai un avviso di conflitto durante l'esecuzione di questo comando (private_pub prova a sovrascrivere il file faye.ru file). Basta digitare "Y" e premere invio, in quanto è necessario sovrascrivere quel file. Avrai anche bisogno di spostare il pubblici / private_pub.js file al app / attività / javascript cartella. E l'ultima cosa: rimuovere la linea che include faye.js sopra application.html.erb, poiché Private Pub lo include automaticamente. Assicurati di riavviare entrambi i server (rails e faye) a questo punto.

Ora, dobbiamo apportare alcune modifiche. Innanzitutto, la sottoscrizione di un utente a un canale viene eseguita in modo diverso con private_pub. modificare app / views / chat / room.html.erb e aggiungi quanto segue prima del blocco JavaScript:

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

Questo è private_pubÈ il modo di iscriversi ai canali. Questo autorizza l'utente a ricevere messaggi attraverso il canale specificato. Ora, abbiamo bisogno di cambiare il codice JavaScript al seguente:

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

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

L'unica differenza qui è che stiamo usando PrivatePub per iscriversi ai canali al posto della libreria Faye direttamente.

Avremo anche bisogno di cambiare il modo in cui pubblichiamo i messaggi. Con Private Pub, solo l'applicazione Rails è in grado di pubblicare messaggi. La libreria Javascript non può pubblicare messaggi autonomamente. Questa è una buona cosa, dal momento che prendiamo il pieno controllo di chi pubblica i messaggi e su quale canale. Per fare questo, avremo bisogno di cambiare il modulo usato per inviare messaggi al seguente:

 <%= form_tag new_message_path, :remote => true do%> <%= text_field_tag :message %> <%= submit_tag "Send" %> <% end %>

Questo è un modulo AJAX, quindi non aggiornerà la pagina quando inviato. Sta anche andando a cercare new_message_path, quindi assicurati di aggiungere questo a routes.rb:

 post '/ new_message' => 'chat # new_message',: as =>: new_message

Avrai anche bisogno di creare un nuovo metodo sul controller chat:

 def new_message # Controlla se il messaggio è privato se recipient = params [: message] .match (/@(.+) (. +) /) # È privato, invialo al canale privato del destinatario @channel = "/ messages /private/#recipient.captures.first "@message = : username => sessione [: username],: msg => recipient.captures.second else # È pubblico, quindi invialo al canale pubblico @channel = "/ messages / public" @message = : username => session [: username],: msg => params [: message] end respond_to do | f | f.js end end

Funziona molto come la sua controparte JavaScript. Determina se il messaggio contiene una menzione e, se lo fa, invia il messaggio al canale privato del destinatario. In caso contrario, invia il messaggio attraverso il canale pubblico. Ora, questo non sta inviando il messaggio, ma crea solo due variabili che dobbiamo usare dalla vista per inviarne una. Pub privato non ti permette di inviare messaggi attraverso il controllore (almeno non con la versione che ho usato per questo tutorial), quindi vai avanti e crea il file app / views / chat / new_message.js.erb e aggiungi il seguente:

 // Cancella l'input del messaggio $ ('# messaggio'). Val ("); // Invia il messaggio <% publish_to @channel, @message %>

Questo eseguirà la prima riga di codice, cancellando la finestra del messaggio e chiamando publish_to, Il pub privato invierà @Messaggio (che verrà convertito in un oggetto JSON quando arriva) a @canale. Semplice, eh?

Vai avanti e provalo. Dovrebbe funzionare come prima, solo con una nuova sicurezza aggiuntiva!


Conclusione

Spero che questo articolo ti abbia fornito alcune informazioni su come utilizzare Faye per i tuoi progetti. Ti consiglio di utilizzare sempre Private Pub, poiché aggiunge un importante livello di sicurezza, a meno che non ne hai davvero bisogno.

Se avete domande, sentitevi liberi di chiedere loro nei commenti o mandarmi un tweet!