or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

connection-management.mdindex.mdjavascript-client.mdrails-integration.mdserver-broadcasting.mdsubscription-adapters.md
tile.json

javascript-client.mddocs/

JavaScript Client

The ActionCable JavaScript client provides a complete browser-side API for establishing WebSocket connections, managing channel subscriptions, and handling real-time communication with ActionCable servers.

Capabilities

ActionCable Global Object

Main entry point for the ActionCable JavaScript client.

// Global ActionCable object
const ActionCable = {
  // Internal configuration constants
  INTERNAL: {
    message_types: {
      welcome: "welcome",
      ping: "ping", 
      confirmation: "confirm_subscription",
      rejection: "reject_subscription"
    },
    default_mount_path: "/cable",
    protocols: ["actioncable-v1-json", "actioncable-unsupported"]
  },
  
  // WebSocket reference
  WebSocket: window.WebSocket,
  
  // Logger reference  
  logger: window.console,
  
  // Create consumer connection
  createConsumer(url?: string): Consumer;
  
  // Get configuration from meta tags
  getConfig(name: string): string | null;
  
  // Convert HTTP URL to WebSocket URL
  createWebSocketURL(url: string): string;
  
  // Enable debug logging
  startDebugging(): void;
  
  // Disable debug logging  
  stopDebugging(): void;
  
  // Log messages if debugging enabled
  log(...messages: any[]): void;
}

Usage Examples:

// Create consumer with default URL (from meta tag)
const consumer = ActionCable.createConsumer();

// Create consumer with specific URL
const consumer = ActionCable.createConsumer('ws://localhost:3000/cable');

// Enable debug logging
ActionCable.startDebugging();

// Get configuration from meta tags
const url = ActionCable.getConfig('url'); // Reads <meta name="action-cable-url">

Consumer

Establishes and manages the WebSocket connection to the ActionCable server.

class Consumer {
  constructor(url: string);
  
  // Connection management
  connect(): void;
  disconnect(): void;
  
  // Send data through the connection
  send(data: object): boolean;
  
  // Ensure connection is active
  ensureActiveConnection(): void;
  
  // Subscription management
  readonly subscriptions: Subscriptions;
  
  // Connection instance
  readonly connection: Connection;
  
  // WebSocket URL
  readonly url: string;
}

Usage Examples:

// Create and connect consumer
const consumer = ActionCable.createConsumer('/cable');

// Send data (rarely used directly)
consumer.send({ command: 'subscribe', identifier: '{"channel":"ChatChannel"}' });

// Disconnect and reconnect
consumer.disconnect();
consumer.connect();

// Ensure active connection before operations
consumer.ensureActiveConnection();

Connection

Internal WebSocket connection management (not typically used directly).

class Connection {
  constructor(consumer: Consumer);
  
  // Connection state
  isOpen(): boolean;
  isActive(): boolean;
  getState(): string;
  getProtocol(): string;
  
  // Connection management
  open(): boolean;
  close(options?: { allowReconnect?: boolean }): void;
  reopen(): void;
  
  // Message transmission
  send(data: object): boolean;
  
  // Connection properties
  readonly consumer: Consumer;
  readonly subscriptions: Subscriptions;
  readonly monitor: ConnectionMonitor;
  readonly disconnected: boolean;
}

Usage Examples:

const consumer = ActionCable.createConsumer();
const connection = consumer.connection;

// Check connection state
if (connection.isOpen()) {
  console.log('Connection is open');
}

console.log('Current state:', connection.getState()); // 'connecting', 'open', 'closed'
console.log('Protocol:', connection.getProtocol()); // 'actioncable-v1-json'

// Force reconnection
connection.reopen();

Connection Monitor

Monitors connection health with heartbeats and handles reconnection.

class ConnectionMonitor {
  constructor(connection: Connection);
  
  // Monitor control
  start(): void;
  stop(): void;
  
  // Connection tracking
  recordConnect(): void;
  recordDisconnect(): void;
  recordPing(): void;
  
  // Monitor state
  isRunning(): boolean;
  
  // Properties
  readonly connection: Connection;
}

Subscriptions

Manages channel subscriptions for a consumer.

class Subscriptions {
  constructor(consumer: Consumer);
  
  // Create subscription to a channel
  create(channelName: string, mixin?: object): Subscription;
  create(channelParams: object, mixin?: object): Subscription;
  
  // Find subscriptions
  findAll(identifier: string): Subscription[];
  
  // Subscription lifecycle
  reload(): void;
  
  // Event notification
  notify(identifier: string, callbackName: string, ...args: any[]): void;
  notifyAll(callbackName: string, ...args: any[]): void;
  
  // Subscription management
  reject(identifier: string): void;
  
  // Properties
  readonly consumer: Consumer;
}

Usage Examples:

const consumer = ActionCable.createConsumer();

// Subscribe to simple channel
const subscription = consumer.subscriptions.create('ChatChannel', {
  received(data) {
    console.log('Received:', data);
  }
});

// Subscribe with parameters
const roomSubscription = consumer.subscriptions.create(
  { channel: 'ChatChannel', room_id: 123 },
  {
    connected() {
      console.log('Connected to chat room');
    },
    
    disconnected() {
      console.log('Disconnected from chat room');
    },
    
    received(data) {
      console.log('Message:', data);
    }
  }
);

// Find all subscriptions for a channel
const chatSubs = consumer.subscriptions.findAll('{"channel":"ChatChannel","room_id":123}');

Subscription

Represents an individual channel subscription.

class Subscription {
  constructor(consumer: Consumer, params: object, mixin?: object);
  
  // Subscription actions
  perform(action: string, data?: object): void;
  send(data: object): boolean;
  unsubscribe(): void;
  
  // Callback methods (implement in mixin)
  connected?(): void;
  disconnected?(data?: { willAttemptReconnect: boolean }): void;
  received?(data: any): void;
  rejected?(): void;
  
  // Properties
  readonly consumer: Consumer;
  readonly identifier: string;
}

Usage Examples:

// Create subscription with callbacks
const subscription = consumer.subscriptions.create('ChatChannel', {
  // Called when subscription is confirmed by server
  connected() {
    console.log('Successfully subscribed to ChatChannel');
  },
  
  // Called when connection is lost
  disconnected(data) {
    console.log('Disconnected. Will reconnect:', data.willAttemptReconnect);
  },
  
  // Called when data is received from the channel
  received(data) {
    console.log('Received message:', data.message);
    document.getElementById('messages').innerHTML += 
      `<div>${data.user}: ${data.message}</div>`;
  },
  
  // Called if subscription is rejected by server
  rejected() {
    console.log('Subscription was rejected');
  }
});

// Send action to channel
subscription.perform('speak', { message: 'Hello everyone!' });

// Unsubscribe when done
subscription.unsubscribe();

Advanced Usage Patterns

Multiple Room Subscriptions

const consumer = ActionCable.createConsumer();
const rooms = {};

function joinRoom(roomId) {
  if (rooms[roomId]) return rooms[roomId];
  
  rooms[roomId] = consumer.subscriptions.create(
    { channel: 'ChatChannel', room_id: roomId },
    {
      connected() {
        console.log(`Joined room ${roomId}`);
      },
      
      received(data) {
        displayMessage(roomId, data);
      },
      
      speak(message) {
        this.perform('speak', { message, room_id: roomId });
      }
    }
  );
  
  return rooms[roomId];
}

function leaveRoom(roomId) {
  if (rooms[roomId]) {
    rooms[roomId].unsubscribe();
    delete rooms[roomId];
  }
}

// Usage
const room1 = joinRoom(1);
const room2 = joinRoom(2);

room1.speak('Hello room 1!');
room2.speak('Hello room 2!');

Connection State Management

const consumer = ActionCable.createConsumer();

// Monitor connection state
consumer.connection.monitor.start();

// Handle connection events
const originalOpen = consumer.connection.events.open;
consumer.connection.events.open = function() {
  console.log('Connection opened');
  document.body.classList.add('connected');
  originalOpen.call(this);
};

const originalClose = consumer.connection.events.close;
consumer.connection.events.close = function(event) {
  console.log('Connection closed');
  document.body.classList.remove('connected');
  originalClose.call(this, event);
};

Custom Authentication

// Consumer with authentication token
const consumer = ActionCable.createConsumer('/cable?token=' + authToken);

// Or using query parameters in subscription
const subscription = consumer.subscriptions.create(
  { 
    channel: 'PrivateChannel',
    token: userToken,
    room_id: roomId 
  },
  {
    connected() {
      console.log('Authenticated and connected');
    },
    
    rejected() {
      console.log('Authentication failed');
      // Redirect to login or show error
    }
  }
);

Error Handling and Reconnection

const consumer = ActionCable.createConsumer();

// Handle connection errors
consumer.connection.events.error = function() {
  console.log('WebSocket error occurred');
  showConnectionError();
};

// Custom reconnection logic
const originalReopen = consumer.connection.reopen;
consumer.connection.reopen = function() {
  console.log('Attempting to reconnect...');
  showReconnectingMessage();
  originalReopen.call(this);
};

// Monitor connection health
setInterval(() => {
  if (!consumer.connection.isActive()) {
    console.log('Connection lost, attempting to reconnect');
    consumer.connection.reopen();
  }
}, 5000);

Integration with Rails

Rails Asset Pipeline

// app/assets/javascripts/cable.js
//= require action_cable
//= require_self
//= require_tree ./channels

(function() {
  this.App || (this.App = {});
  
  App.cable = ActionCable.createConsumer();
}).call(this);

Channel-specific JavaScript

// app/assets/javascripts/channels/chat.js
App.chatChannel = App.cable.subscriptions.create('ChatChannel', {
  connected: function() {
    console.log('Connected to ChatChannel');
  },

  disconnected: function() {
    console.log('Disconnected from ChatChannel');
  },

  received: function(data) {
    console.log('Received data:', data);
  },

  speak: function(message) {
    return this.perform('speak', { message: message });
  }
});

Meta Tag Configuration

<!-- In Rails layout -->
<%= action_cable_meta_tag %>
<!-- Generates: <meta name="action-cable-url" content="/cable" /> -->