Guías de Make it Real
  • Introduction
  • Preparación
    • Conceptos básicos
    • El editor de texto
    • La línea de comandos
    • Git y Github
  • Git
    • Instalación y configuración
    • Conceptos y comandos esenciales
    • Ignorando archivos y carpetas
    • Trabajando con ramas
    • Repositorios remotos
    • Etiquetas
    • Reescribiendo la historia
    • Stashing
    • Github
  • HTML y CSS
    • Introducción a HTML
    • Introducción a CSS
    • Más elementos de HTML
    • Tablas
    • Formularios
    • El modelo de caja en CSS
    • Fondos (backgrounds)
    • Posicionamiento
    • Selectores CSS
    • Bordes, sombras y gradientes
    • Media Queries
    • Unidades en CSS
    • Flexbox
  • Bootstrap 3
    • Primeros pasos
    • Elementos básicos de HTML
    • Componentes
    • La grilla
    • Personalizando Bootstrap
    • Utilizando plantillas
  • Bootstrap 4
    • Primeros pasos
    • Elementos básicos de HTML
    • Componentes
    • La grilla
    • Clases utilitarias
    • Personalizando Bootstrap
  • Ruby
    • Primeros pasos
    • Tipos y operadores
    • Variables y entrada de usuario
    • Condicionales
    • Ciclos
    • Arreglos
    • Más cadenas de texto
    • Hashes
    • Métodos
    • Manipulación de archivos
    • Gemas
  • Programación Orientada a Objetos en Ruby
    • Clases y objetos
    • Métodos y atributos de clase
    • Herencia
    • Módulos
    • Excepciones
  • JavaScript I
    • Primeros pasos
    • Tipos y operadores
    • Variables
    • Condicionales
    • Ciclos
    • Arreglos
    • Más cadenas de texto
    • Funciones
    • Objetos literales
    • Manipulación de archivos
  • JavaScript en el navegador
    • Primeros pasos
    • Manipulando HTML
    • Escuchando eventos
    • Local Storage
    • History API
    • Canvas
    • Notificaciones Web
    • Audio y Video
    • Arrastrar y soltar
    • JSON
    • Realizando peticiones HTTP
  • jQuery
    • Primeros pasos
    • Manipulando HTML
    • Escuchando eventos
    • Plugins
    • Realizando peticiones con AJAX
  • JavaScript II
    • Prototipos
    • Librerías (Node.js)
    • ES6
    • Uso de this (call, apply, bind)
    • Programación funcional
    • Scope, hoisting, closures
    • Programación asincrónica
    • Testing
  • HTTP y Sinatra
    • Primeros pasos con Sinatra
    • El protocolo HTTP
    • Rutas
    • Formularios
    • Cookies y sesión
  • Bases de datos
    • Bases de datos relacionales
    • SQL
    • DDL
    • MongoDB
  • Ruby on Rails I
    • Primeros pasos
    • Arquitectura
    • Rutas
    • Layouts y rendering
    • ActiveRecord - Modelos
    • ActiveRecord - Migraciones
    • ActiveRecord - Validaciones
    • ActiveRecord - Asociaciones
    • ActiveRecord - Scopes
    • ActiveRecord - Callbacks
    • Recursos REST
    • Formularios
    • Autenticación con Devise
    • Sass y Bootstrap
    • Envío de correos
    • Carga de imágenes
    • Seeds
    • Heroku
  • Ruby on Rails II
    • Usando JavaScript (y jQuery) en Rails
    • Testing en Ruby
    • Testing en Rails
    • Creando una Web API
    • Web Sockets
  • Express.js
    • Primeros Pasos
    • El protocolo HTTP
    • Rutas
    • Vistas
    • Middlewares y manejo de errores
    • Formularios
    • Cookies y sesión
  • Express.js II
    • Mongoose
    • Web Sockets
    • Autenticación
    • Envío de correos
    • Cargar imágenes
    • Deployment
    • Testing
    • Creando una Web API
  • React
    • Primeros pasos
    • JSX
    • Componentes
    • Más sobre estado
    • Formularios
    • Peticiones HTTP con Axios
    • React Hooks
    • React Context
    • React Bootstrap
    • React Router
    • Carga de Imágenes
    • Testing
    • Estructura de carpetas
    • Componentes de clase
  • Redux
    • Primeros pasos
    • Action creators
    • Usando la librería react-redux
    • Middlewares
    • Operaciones asincrónicas con redux-thunk
    • Combinando funciones reductoras
    • Testing
    • Redux Tool Kit
  • Algoritmos
    • Describiendo un algoritmo
    • Complejidad (Big-O)
    • Estructuras de datos
    • Recursión
    • Ordenamiento
    • Búsqueda
    • Programación dinámica
  • Python
    • Primeros Pasos
    • Tipos y Variables
    • Funciones
    • Control de Flujo
    • Listas
    • Ciclos
    • Diccionarios, Tuplas y Sets
  • NumPy
    • Primeros Pasos
    • Arreglos
    • Arreglos Multidimensionales
    • Estadística con NumPy
    • Distribución Estadística
  • Pandas
    • Primeros Pasos
    • Inspección y Selección de Datos
    • Modificando Dataframes
    • La Función Lambda
    • Aggregates en Pandas
    • Múltiples Tablas
Powered by GitBook
On this page
  • Conceptos básicos
  • Nuestro primer canal
  • Enviando información al cliente (desde el servidor)
  • Recibiendo información en el cliente
  • Enviando información al servidor (desde el cliente)
  • Recibiendo información en el servidor
  • Parametrizando los canales
  • Identificando las conexiones
  • Comunicación entre procesos
  1. Ruby on Rails II

Web Sockets

PreviousCreando una Web APINextExpress.js

Last updated 2 years ago

Web Sockets es una tecnología que permite a los navegadoress recibir información del servidor y actualizarse en tiempo real, sin necesidad de refrescar la página.

La forma en que funciona Web Sockets es que el navegador, a través de JavaScript, abre una conexión HTTP con el servidor y mantiene esa conexión abierta para que el servidor pueda enviarle información al navegador en cualquier momento (el cliente también puede enviarle información al servidor a través de esta conexión).

Para que Web Sockets funcione se debe escribir código tanto en el cliente (con JavaScript o CoffeeScript) como en el servidor (p.e. con Ruby).

Rails 5 introduce , un módulo que facilita la implementación de WebSockets en nuestras aplicaciones.

Conceptos básicos

Antes de empezar a trabajar con Action Cable debes conocer los siguientes conceptos:

  • Connection: representa la conexión HTTP entre el cliente y servidor, generalmente se abre una única conexión por sesión (por pestaña del navegador).

  • Channel: los canales son lo equivalente a los controladores en Rails, nos permiten organizar la comunicación entre el servidor y los clientes.

  • Subscription: los clientes realizan subscripciones a los canales de los cuáles les interesa recibir información.

Nuestro primer canal

Lo primero que debemos pensar en nuestras aplicaciones es qué canales vamos a necesitar crear.

Por ejemplo, si estamos creando un sistema de chat con "cuartos" donde varias personas pueden interactuar en un mismo cuarto, podríamos pensar en un canal llamado Room que represente cada cuarto que se cree. Cuando un usuario ingresa a un cuarto se suscribe al canal de ese cuarto para recibir los mensajes de otras personas.

Para crear un canal se puede utilizar el siguiente generador para canales:

$ rails generate channel room

El comando anterior crea dos archivos:

  • app/channels/room_channel.rb - nos permite configurar el canal y recibir información del cliente desde el servidor.

  • app/assets/javascripts/channels/room.coffee - crea la conexión al canal y nos permite enviar y recibir información al servidor (desde el cliente).

Ahora podemos empezar a enviar información del servidor al cliente y viceversa!

Nota: Con el comando anterior se crea un único canal al que todos los clientes se van a conectar automáticamente. Más adelante vamos a ver cómo pasarle parámetros a los canales.

Enviando información al cliente (desde el servidor)

Para enviar un mensaje a todos los clientes conectados a un canal utilizamos el método ActionCable.server.broadcast desde cualquier canal, controlador, modelo o helper:

data = { message: "Hola Amigos", user: "pedro0553" }
ActionCable.server.broadcast("RoomChannel", data)

Nota: Estas líneas no las puedes ejecutar desde rails console ni desde un background job. Para hacerlo debes utilizar Redis como vamos a ver el final de este capítulo.

Recibiendo información en el cliente

Para recibir información en el cliente se debe modificar el archivo que fue generado para el cliente cuando se creó el canal, en nuestro ejemplo app/assets/javascripts/channels/room.coffee:

App.room = App.cable.subscriptions.create "RoomChannel",
  connected: ->

  disconnected: ->

  received: (data) ->
    console.log(data); # acá recibimos la información

El método received se llama cada vez que se recibe un mensaje del servidor. En este caso estamos haciendo un console.log pero acá podemos, por ejemplo, modificar el HTML para mostrar el mensaje.

Enviando información al servidor (desde el cliente)

Para enviar información al servidor utilizamos el método send sobre el canal desde cualquier archivo JavaScript (o CoffeeScript). En nuestro ejemplo anterior sería de la siguiente forma:

App.room.send({ message: "Hola a todos", user: "miguel8734" });

Estamos utilizando App.room porque así se llama la variable en app/assets/javascripts/channels/room.coffee.

Recibiendo información en el servidor

Para recibir información en el servidor se debe modificar el archivo que fue generado para el servidor cuando se creó el canal, en nuestro ejemplo app/channels/room_channel.rb:

class RoomChannel < ApplicationCable::Channel
  def subscribed
  end

  def unsubscribed
  end

  def received(data)
    puts data # acá recibimos la información del cliente
  end
end

El método received se llama cada vez que recibimos información del cliente.

Parametrizando los canales

Nuestro ejemplo anterior no es muy útil porque sólo soporta un "cuarto". Generalmente queremos que los canales soporten parámetros (p.e. el id o el nombre del cuarto en nuestra aplicación de chat).

Para soportar parámetros en nuestros canales debemos modificar tanto el servidor como el cliente.

En el servidor vamos a modificar el método subscribed de nuestro canal en app/channels/room_channel.rb:

class RoomChannel < ApplicationCable::Channel
  def subscribed
    stream_from "room-#{params[:name]}"
  end
end

El método stream_from nos permite nombrar el canal y utilizar parámetros en el nombre.

En el cliente vamos a modificar la forma en que nos suscribimos al canal en app/assets/javascripts/channels/room.coffee:

App.room = App.cable.subscriptions.create { channel: "RoomChannel", name: "micuarto" },
  connected: ->

  disconnected: ->

  received: (data) ->
    console.log(data); # acá recibimos la información

En vez de pasarle un string al método create le vamos a pasar un objeto que tiene el canal y cualquier parámetro adicional que necesitemos (en este caso el name con valor "micuarto").

Sin embargo, no queremos que siempre se conecte al cuarto micuarto, así que lo mejor sería encapsular el código de la suscripción en una función que podamos llamar desde otra parte de nuestro código JavaScript. Modifiquemos room.coofee:

window.subscribeToRoom = (room) => {
  App.room = App.cable.subscriptions.create { channel: "RoomChannel", name: room },
    connected: ->

    disconnected: ->

    received: (data) ->
      console.log(data); # acá recibimos la información
}

Y más adelante en nuestro código (p.e. cuando la persona entre a un cuarto):

subscribeToRoom("micuarto");

Nota: En este ejemplo hemos almacenado la función en window, quizá una mejor práctica es almacenarla en App o en otro objeto para no contaminar el contexto global.

Identificando las conexiones

En la mayoría de aplicaciones vamos a necesitar identificar cada conexión (p.e. para saber qué usuario es).

Para identificar las conexiones vamos a modificar el archivo app/channels/application_cable/connection.rb:

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = User.find_by(id: cookies.encrypted[:user_id])
    end
  end
end

En este ejemplo estamos identificando la conexión utilizando una variable current_user que inicializamos en el método connect (es decir, cuando se abre la conexión con el servidor). Fíjate que es necesario acceder a las cookies para encontrar el id del usuario.

Nota: Ojalá más adelante integren Action Cable con Devise para no tener que hacer este paso manualmente y que la autenticación funcione como funciona en los controladores!

Comunicación entre procesos

Por defecto, la configuración de Action Cable se encuentra en el archivo config/cable.yml, que se puede configurar de la siguiente manera:

development:
  adapter: async

test:
  adapter: async

production:
  adapter: redis
  url: redis://10.10.3.153:6381
  channel_prefix: appname_production

El adaptador async es para desarrollo y testing, no para producción. Este adaptador no permite la comunicación entre procesos.

El adaptador redis se recomienda para producción y si quieres probar el broadcast desde rails console o desde un background job.

Para desplegar en producción (p.e. en Heroku) o para probar desde rails console debes instalar y utilizar .

Action Cable
Redis