Se você quer criar um chat em tempo real, ou então criar um joguinho multiplayer, então para fazer em Rails, será necessário usar o Action Cable.
Então, vamos lá.
O que é Action Cable?
Action Cable integra perfeitamente com WebSockets com o resto da sua aplicação Rails. Isso permite que recursos em tempo real sejam escritos em Ruby no mesmo estilo da sua aplicação, enquanto ainda é performático e escalável. Isso é uma oferecimento full-stack que providencia o framework Javascript do client-side e framework Ruby do server-side.
Agora, que nós sabe o que é Action Cable, vamos entender algumas termologias.
Termologias
Connections ou Conexões
Connections (Conexões) formam a base do relacionamento cliente-servidor. Um único servidor Action Cable pode lidar com várias instâncias de conexão. Um único usuário pode ter vários WebSockets abertos para seu aplicativo se usar várias abas do navegador ou dispositivos diferentes.
Consumers ou consumidores
O cliente de uma conexão WebSocket é chamado de consumer (consumidor). Em Action Cable, o consumer é criado pelo framework javascript do client-side
Channels ou Canais
Cada consumer pode, por sua vez, assinar vários channels.
Cada canal encapsula uma unidade lógica de trabalho, similar o que controller faz no típico MVC. Por exemplo, você pode ter um ChatChannel
e um PresencaChannel
e um consumer pode assinar um ou ambos canais. No minimo, o consumer deve assinar pelo menos um canal.
Subscribers ou Assinantes
Quando o consumer está assinado em um channel, ele pode agir como um subscriber (assinante). A conexão entre o subscriber e o channel é, surprise-surprise, chamado de assinatura. Um consumer pode agir como um subscriber de um determinado channel quantas vezes quiser. Por exemplo, um consumer pode assinar várias sala de conversa ao mesmo tempo.
Pub/Sub
Pub/Sub ou Publish-Subscribe (Publicar-Assinar) refere-se a uma paradigma de fila de messagens por meio do qual os remetentes de informações (publishers), enviam dados apara uma classe abstrata de destinatários (subscribers), sem especificar os destinatários individuais. Action Cable usa essa abordagem para comunicar entre o servidor e vários clientes.
Broadcastings ou Transmissões
Um broadcasting é um link pub/sub em que qualquer coisa transmitida pelo broadcaster é enviada diretamente para os subscribers do channel que estão transmitindo essa chamada broadcasting. Cada canal pode transmitir zero ou mais broadcastings.
Tendo o conhecimento das termologias, vamos criar uma aplicação.
Criando uma aplicação
O aplicativo que vou criar é um chat.
rails new chat
cd chat
rails g controller Chat index
Coloque a rota chat#index
como root.
# config/routes.rb
Rails.application.routes.draw do
root 'chat#index'
end
Abra o arquivo app/views/chat/index.html.erb
e coloque o código abaixo.
<!-- app/views/chat/index.html.erb -->
<div>
<textarea id="input"></textarea>
<button id="button">enviar</button>
</div>
<div id="chat"></div>
Agora, vamos colocar o Action Cable.
Instalando o Action Cable
Como a nossa aplicação é um chat, então vamos criar um channel Chat.
Para criar, basta usar o generator.
rails g channel Chat
Tem um arquivo que fica no app/channels/application_cable/connection.rb
que fica responsável pela conexão.
Porém, você tem fazer a parte de autenticação e autorização, mas como a minha aplicação não tem autenticação, então eu vou ignorar essa parte.
Mas eu vou deixar um exemplo do código de como seria se tivesse uma autenticação.
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
private
def find_verified_user
# se você estiver usando cookie para autenticação
verified_user = User.find_by(id: cookies.encrypted[:user_id])
# se você estiver usando session para autenticação
verified_user = User.find_by(id: cookies.encrypted['_session']['user_id'])
# se por acaso, você estiver usando uma gem para autenticação, terá pesquisar sobre isso.
if verified_user
verified_user
else
reject_unauthorized_connection
end
end
end
end
Você pode observar o identified_by
, ele cria um identificador de conexão, ou seja, você pode usar current_user
para saber quem é o usuário que está conectado em uma conexão.
Agora, vamos focar no client-side.
Client Side
Abra o arquivo app/javascript/channels/chat_channel.js
e coloque o código abaixo.
// app/javascript/channels/chat_channel.js
import consumer from "channels/consumer"
// o consumer vai ser criado aqui e vai tentar assinar no canal ChatChannel
consumer.subscriptions.create("ChatChannel", {
connected() { // vai executar essa método se a conexão foi sucedida
this.input = document.getElementById("input")
this.chat = document.getElementById("chat")
const button = document.getElementById("button")
button.addEventListener("click", this.enviar_mensagem.bind(this))
},
received(dados) { // Aqui recebe os dados do server side
this.chat.innerHTML += `<p>${dados.mensagem}</p>`
},
enviar_mensagem() { // Aqui vai enviar os dados para server side
let dados = {mensagem: input.value}
this.perform("mensagem", dados)
// isso vai enviar os dados para action mensagem do server side
input.value = ""
}
});
Server side
Abra o arquivo app/channels/chat_channel.rb
e coloque o código abaixo.
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
# vai executar esse método se o usuário vai fazer uma conexão
def subscribed
# o stream_from vai assina em um broadcasting com nome 'chat', isso é útil para criar grupo.
stream_from "chat"
end
# aqui é a action que recebe os dados do client side
def mensagem dados
# isso vai envia a dados para os subscribers (assinantes). O primeiro argumento é o nome do broadcasting, como você pode ver que é igual ao argumento do `stream_from`.
ActionCable.server.broadcast("chat", dados)
end
end
Agora, execute o rails server
e abre duas abas do navegador com a url localhost:3000
, tente manda uma mensagem e verá que a outra aba vai receber a mensagem.
Com isso, nós terminamos por aqui, porém eu vou fazer, um dia, um post, em que vou aprofundar mais o action cable criando um joguinho simples.
Então é isso, tchau!
Top comments (3)
Obrigado pela explicação! Gostaria de pedir a continuação, pfv!
Bem, posso até tentar, mas como eu estou um pouco ocupado agora e, além disso, não mexo com Rails desde o ano passado e também não sei se houve alguma atualização sobre isso, mas tentarei.
Infelizmente, não vou fazer isso, porque ainda não abordei o Redis, banco de dados e a utilização de JavaScript no Rails. Afinal, não gosto de abordar assuntos que não foram apresentados e não tenho tempo para isso. Então é isso.